Meteor Collection具有转换能力,允许将行为附加到从mongo返回的对象。
我们希望关闭自动发布,以便客户端无法访问数据库集合,但我们仍然需要转换功能。
我们使用更明确的 Meteor.publish/Meteor.subscribe 或 RPC 机制( Meteor.call()/Meteor.methods() )向客户端发送数据
我们如何让 Meteor 客户端自动应用转换,就像直接使用 Meteor.Collection 方法检索数据时一样?
虽然不能直接使用转换,但有一种方法可以在发布数据库查询结果之前对其进行转换。这就是此处描述的"发布集合的当前大小"示例。
我花了一段时间才想出一个非常简单的应用程序,所以也许我的代码也会帮助你:
Meteor.publish("publicationsWithHTML", function (data) {
var self = this;
Publications
.find()
.forEach(function(entry) {
addSomeHTML(entry); // this function changes the content of entry
self.added("publications", entry._id, entry);
});
self.ready();
});
在您订阅以下内容的客户端上:
Meteor.subscribe("publicationsWithHTML");
但是您的模型仍然需要创建一个称为"发布"的集合(在两侧):
Publications = new Meteor.Collection('publications');
请注意,这不是一个很好的例子,因为它不能保持反应性。但是一开始我发现计数示例有点令人困惑,所以也许您会发现它很有帮助。
(Meteor 0.7.0.1) - Meteor 确实允许将行为附加到通过 pub/sub 返回的对象。
这是来自我提交给流星项目的拉取请求。
Todos = new Meteor.Collection('todos', {
// transform allows behavior to be attached to the objects returned via the pub/sub communication.
transform : function(todo) {
todo.update = function(change) {
Meteor.call('Todos_update', this._id, change);
},
todo.remove = function() {
Meteor.call('Todos_remove', this._id);
}
return todo;
}
});
todosHandle = Meteor.subscribe('todos');
通过"todos"主题返回的任何对象都将具有 update() 和 remove() 函数 - 这正是我想要的:我现在将行为附加到返回的数据。
尝试:
let transformTodo = (fields) => {
fields._pubType = 'todos';
return fields;
};
Meteor.publish('todos', function() {
let subHandle = Todos
.find()
.observeChanges({
added: (id, fields) => {
fields = transformTodo(fields);
this.added('todos', id, fields);
},
changed: (id, fields) => {
fields = transformTodo(fields);
this.changed('todos', id, fields);
},
removed: (id) => {
this.removed('todos', id);
}
});
this.ready();
this.onStop(() => {
subHandle.stop();
});
});
目前,无法将服务器上的转换应用于已发布的集合。有关更多详细信息,请参阅此问题。这样,您要么转换客户端上的数据,要么使用 meteor 方法。在方法中,您可以让服务器对数据执行任何操作。
在我的一个项目中,我们通过方法调用执行最昂贵的查询(它联接多个集合、非规范化文档并修剪不必要的字段)。它不是反应式的,但它大大简化了我们的代码,因为所有的转换都发生在服务器上。
扩展@Christian弗里茨答案,使用 peerlibrary:reactive-publish
Meteor.publish("todos", function() {
const self = this;
return this.autorun(function(computation) {
// Loop over each document in collection
todo.find().forEach(function(entry) {
// Add function to transform / modify each document here
self.added("todos", entry._id, entry);
});
});
});