我有一个发布,其范围取决于另一个集合的元素属性。基本上它在服务器上看起来像这样:
Meteor.publish('kids', function (parent) {
return Kids.find({ _id: { $in: parent.childrenIds } });
}
在上面的示例中,parent.childrenIds
是一个数组,其中包含父母子女的所有孩子的_id。这工作正常,直到我想要向父母添加一个新的孩子:
newKidId = Kids.insert({ name: 'Joe' });
Parents.update({ _id: parentId }, { $push: { childrenIds: newKidId } });
这适用于Kids
集合的服务器(即添加了新的孩子),并使用{更新了父{q} childrenIds
数组{1}}。但它没有更新上述“孩子们”。发布(光标未更新/修改)。因此,客户端的newKidId
集合未更新(看起来对Kids
的更改将在客户端上回滚。)
当客户端刷新时,所有发布都会停止/重新启动,新的孩子(Joe)最终会发布到客户端。
有没有办法避免刷新客户端并强制重新发布Kids
集合(理想情况下只将新的孩子Joe发送给客户端)?
答案 0 :(得分:7)
Meteor中经常被误解的一个问题是服务器上没有反应性。动态描述需要由客户端上的Deps.autorun
块处理。为此,首先确保在项目目录中使用此命令不包括autopublish包:
$ meteor remove autopublish
其次,在客户端上设置一个自动运行块,如:
Meteor.startup(function(){
Meteor.subscribe('parents');
Deps.autorun(function() {
parent = Parents.findOne();
if (!parent) return;
Meteor.subscribe('kids', parent);
});
});
这将在父对象更改时拆除并设置订阅。
您可以在https://gist.github.com/jagill/5473599找到完整的工作示例。
答案 1 :(得分:1)
与此同时,还有一些用于处理反应式发布功能的软件包。我是meteor-related的作者,在包的自述文件的最后,我将我的包与其他几个包进行比较:
答案 2 :(得分:0)
我认为如果发布的查询依赖于第二个查询,则需要在发布函数中使用observe。客户端上的Deps.autorun不是必需的。
查看有关Meteor server reactivity和Reactive updates when query is filtered by another query的讨论。
这是一些基于http://docs.meteor.com'逐个房间'示例的代码。
Meteor.publish( "kids", function(parent_id){
var self = this;
Parents.find({_id: parent_id}, { childrenIds: 1 }).observe({
added: function (document){
document.childrenIds.forEach( function(kidId){
self.added("kids", kidId, Kids.findOne( { _id: kidId}, {name: 1, _id: 1} ));
});
},
removed: function (oldDocument){
oldDocument.childrenIds.forEach( function(kidId){
self.removed("kids", kidId, Kids.findOne( { _id: kidId}, {name: 1, _id: 1} ));
});
},
changed: function (newDocument, oldDocument){
var oldLength = oldDocument.childrenIds.length;
var newLength = newDocument.childrenIds.length;
if (newLength > oldLength){
self.added("kids",
newDocument.childrenIds[newLength-1],
Kids.findOne( { _id: newDocument.childrenIds[newLength-1] }, {name:1, _id:1}) );
}
else{
self.removed("kids",
oldDocument.childrenIds[oldLength-1],
Kids.findOne( { _id: oldDocument.childrenIds[oldLength-1] }, {name:1, _id:1}) );
}
}
});
self.ready();
});
答案 3 :(得分:0)
这些天你可以简单地使用reactive-publish包(我是作者之一):
Meteor.publish('kids', function (parentId) {
this.autorun(function (computation) {
var parent = Parents.findOne(parentId, {fields: {childrenIds: 1}});
return Kids.find({_id: {$in: parent.childrenIds}});
});
}
将Parents
'查询字段限制为childrenIds
非常重要,这样autorun
不会重新运行Parents
文档的任何其他更改。