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在客户端上回滚了)。

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

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

4

4 回答 4

7

Meteor 中经常被误解的一件事是服务器上没有反应性。动态描述需要由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看到一个完整的工作示例。

于 2013-04-27T16:01:54.780 回答
1

与此同时,有相当多的包用于处理响应式发布功能。我是meteor-related的作者,在包的自述文件末尾,我将我的包与其他几个包进行了比较:

于 2015-01-18T01:37:41.857 回答
0

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

当查询被另一个查询过滤时,请参阅有关 Meteor 服务器反应性和反应性更新的讨论。

这是一些基于http://docs.meteor.com 'counts-by-room' 示例的代码。

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();      
});
于 2013-04-29T13:55:53.047 回答
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文档的任何其他更改。

于 2015-10-03T10:36:02.767 回答