在每个文档中构建一个包含附加字段的反应性出版物

Build a reactive publication with additional fields in each document

我想制作一个包含多个附加字段的出版物,但我不想使用 Collection.aggregate 并在集合更改时丢失我的出版物更新(所以我不能只使用 self.added 在里面)。

我打算使用 Cursor.observeChanges 来实现这一点。我有两个主要限制:

  1. 我不想发布所有文档字段
  2. 我想使用一些未发布的字段来创建新的字段。例如,我有一个字段 item,我在其中存储一个 item _id 的数组。我不想发布它,但我想发布一个 item_count 字段,其长度为我的字段数组

方法来了:

  1. 我打算链接查找查询。我从来没有这样做过,所以我想知道这是否可能。一般(简化的)查询结构是这样的:http://jsfiddle.net/Billybobbonnet/1cgrqouj/(我无法在此处正确显示代码)

  2. 基于the count example in Meteor documentation,我将查询存储在变量handle中,以便在客户端取消订阅时停止更改通知:

self.onStop(function () {
  handle.stop();
});
  1. 我在查询之前添加了一个标志 initializing = true;,并在调用 self.ready(); 之前将其设置为 true。仅当发布已初始化时,我才使用此标志更改我的 itemCount 变量。所以基本上,我像这样更改 switch
switch (field) {
  case "item"
    if (!initializing)
      itemCount = raw_document.item.length;
      break;
  default:
}

在对我的代码进行重大更改之前,我想检查一下这种方法是否可行。如果这是正确的方法,有人可以确认我吗?

要解决您的第一个问题,您需要告诉 MongoDB 它应该 return 游标中的哪些字段。省略不需要的字段:

MyCollection.find({}, {fields: {'a_field':1}});

解决你的第二个问题也很简单,我建议使用collection helpers packages。您可以像这样轻松完成此操作:

// Add calculated fields to MyCollection.
MyCollection.helpers({
  item_count: function() {
    return this.items.length;
  }
});

这将是 运行 在将对象添加到游标之前,并将在动态计算的 returned 对象上创建属性,而不是存储在 MongoDB 中。

保持字段私有相对容易,即使它们是数据库查询的一部分。 self.added 的最后一个参数是传递给客户端的对象,因此您可以 strip/modify/delete 发送给客户端的字段。

这是您的 fiddle 的修改版本。这应该做你所要求的。 (老实说,我不确定为什么你在 fiddle 中的 observeChanges 函数之后链接了任何东西,所以也许我误解了你,但看看你的问题的其余部分应该是这样.如果我说错了请见谅。)

var self = this;

// Modify the document we are sending to the client.
function filter(doc) {
  var length = doc.item.length;

  // White list the fields you want to publish.
  var docToPublish = _.pick(doc, [
      'someOtherField'
  ]);

  // Add your custom fields.
  docToPublish.itemLength = length;

  return docToPublish;                        
}

var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
            // Use observe since it gives us the the old and new document when something is changing. 
            // If this becomes a performance issue then consider using observeChanges, 
            // but its usually a lot simpler to use observe in cases like this.
            .observe({
                added: function(doc) {
                    self.added("myCollection", doc._id, filter(doc));
                },
                changed: function(newDocument, oldDocument)
                    // When the item count is changing, send update to client.
                    if (newDocument.item.length !== oldDocument.item.length)
                        self.changed("myCollection", newDocument._id, filter(newDocument));
                },
                removed: function(doc) {
                    self.removed("myCollection", doc._id);                    
                });

self.ready();

self.onStop(function () {
  handle.stop();
});