如何处理Meteor中的动态订阅?

时间:2013-04-27 12:25:14

标签: meteor

我有一个发布,其范围取决于另一个集合的元素属性。基本上它在服务器上看起来像这样:

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发送给客户端)?

4 个答案:

答案 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 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();      
});

答案 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文档的任何其他更改。