2013-04-27 109 views
2

我有一个出版物,其范围取决于另一个集合的元素属性。基本上,它看起来像这样在服务器上:如何处理流星中的动态订阅?

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集合(即,新的孩子加入),并将其与更新父childrenIds阵列newKidId。但它不会更新上面的'孩子'出版物(光标不更新/修改)。因此,客户端Kids集合未更新(并且看起来像在客户端上回滚到Kids的更改)。

当客户端刷新时,所有发布都会停止/重新启动,并且新的孩子(Joe)最终会发布到客户端。

有没有办法避免刷新客户端并强制重新发布Kids集合(理想情况下只发送新的孩子乔到客户端)?

回答

0

这几天你可以简单y使用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文件。

7

流星误区之一是在服务器上没有任何反应。动态描述需要由客户端上的Deps.autorun块处理。要做到这一点,首先要确保你不包括自动发布包在项目目录使用这个命令:

$ 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看到一个完整的工作示例。

+0

感谢jigill对于这个要点 - 它确实有效。现在,您的服务器代码确实依赖于发送正确的“父对象”的客户端来确定“parent.childrenIds”中的(最新)密钥是什么。这是一个安全漏洞。你会如何检查服务器上的父母确实已经更新了那个特定的孩子?我尝试传递'parent._id'(并修改Kids出版物),但它打破了预期的行为(请参阅https://gist.github.com/jbmoens/5476431 - 我已评论我的编辑) – 2013-04-28 09:45:44

+0

这是一个单独的问题,我很乐意回答。但最好将其作为一个新问题发布,接受/关闭此问题。 – jagill 2013-04-28 21:21:31

+0

完成 - 看[这里](http://stackoverflow.com/questions/16274226/how-to-make-dynamic-subscriptions-secure-in-meteor) – 2013-04-29 08:29:07

0

我认为如果发布的查询依赖于第二个查询,您需要在发布函数中使用观察。客户端上的Deps.autorun不是必需的。

查看关于Meteor server reactivityReactive 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();  
});