【问题标题】:Associate each model returned by a Meteor collection's subscription关联 Meteor 集合订阅返回的每个模型
【发布时间】:2016-12-16 15:45:12
【问题描述】:

在我目前正在开发的 Meteor 应用程序中,某些集合可能有多个同时订阅(即一个用于初始获取,另一个用于搜索更多数据等)。当然,我不希望将整个集合下载到客户,所以我依靠subscriptions manager 和一种需要的方法。

问题是,一旦获取数据,客户端上的集合包含所有订阅的全部内容,我不确定如何辨别哪些数据是从哪个订阅获取的(即最初获取了哪些数据,以及被搜索的内容等)

我曾考虑为每个获取的数据(一个数组,因为可以从多个订阅中获取一些数据)添加一个订阅 UID,但这似乎很麻烦,而且容易清理地狱。

是否有解决方案来关联和识别哪个订阅获取了哪些数据?


更新

到目前为止,this answer 似乎解决了部分问题,但这不是我认为“干净”的解决方案。

// ctx being the Metheor.subscribe context (i.e. const ctx = this;)

function transform(doc) {
  if (searchKey) {
    doc._searchKey = searchKey;
  }
  return doc;
}

const cursor = InventoryItems.find(filter, options);
const observer = cursor.observe({
  added(doc) {
    ctx.added(InventoryItems._name, doc._id, transform(doc));
  },
  changed(newDoc, oldDoc) {
    ctx.changed(InventoryItems._name, newDoc._id, transform(newDoc));
  },
  removed(oldDoc) {
    ctx.removed(InventoryItems._name, oldDoc._id);
  }
});

ctx.onStop(() => {
  observer.stop();
});

return cursor;

【问题讨论】:

  • 有趣的问题。我从未见过需要这种模式。为什么这有关系?由于不同的订阅可以在同一个文档中为您提供不同的密钥,因此管理起来似乎很麻烦。我在想转换可能会有所帮助,但可能不会。
  • 我宁愿不使用转换,但如果我别无选择......我曾经使用转换来规范化我的数据,但后来我失去了数据的反应性。我现在依靠publish composite 来管理规范化。因此,如果我获取(例如)一个帖子,它将自动获取关联的用户。然后,如果我搜索用户,我会搜索到所有用户,以及与帖子关联的用户......两个订阅,一个集合。
  • 为什么需要辨别数据的来源?数据的结构是否仍以相同的方式具有相同的含义?如果没有,可能需要将某些东西重组到它自己的集合中。
  • @TravisWhite 我可能不明白其他人是怎么做的,或者 Meteor 的文档不够清楚......我正在开发的应用程序是供内部使用的,并且依赖于反应性;您修改某些内容,应通知其他客户。因此,我不能指望在少数情况下进行非规范化。例如,应该增加一些库存商品的订单需要知道每个商品的状态,如果添加了商品,用户将搜索库存(从而创建搜索条件的新订阅),这将添加到单例收藏。不能有两个集合。
  • @YanickRochon 我想我只是想知道用例来帮助理解更大的图景。为什么需要知道数据是通过订阅 1 还是订阅 2 返回的?最新订单是最新订单,无论哪个订阅返回它......还是我错过了什么?

标签: mongodb meteor subscription


【解决方案1】:

此答案描述了一种将数据发布到仅限客户端的集合的方法。

如果要分离部分数据,可以发布到不同的集合:

//client

const TempCollection = new Meteor.Collection('temp', {defineMutationMethods: false});

Meteor.subscribe('temp.query', 'queryParams');

这定义了一个没有设置突变方法的集合,因此在客户端对其进行的任何更改都不会发送到服务器(因为这将毫无意义)。请注意,在服务器发布中应使用集合名称(本例中为 temp)。

// server
const ActualCollection = new Mongo.Collection('real_collection_name');

function publishForTarget(sub, cursor, targetName) {
    return Mongo.Collection._publishCursor(cursor, sub, targetName);
}

Meteor.publish('temp.query', function(/*params*/) {
    let query = {/*...*/};
    let targetName = 'temp'; // or get it from the client for dynamically-named client-side collections. 
    let cursor = ActualCollection.find(query);    
    publishForTarget(this, cursor, targetName);

    return this.ready();
});

这使用未记录的Mongo.Collection._publishCursor 方法,标准发布在返回游标时也使用该方法。

它的实现:

Mongo.Collection._publishCursor = function (cursor, sub, collection) {
  var observeHandle = cursor.observeChanges({
    added: function (id, fields) {
      sub.added(collection, id, fields);
    },
    changed: function (id, fields) {
      sub.changed(collection, id, fields);
    },
    removed: function (id) {
      sub.removed(collection, id);
    }
  });

  // We don't call sub.ready() here: it gets called in livedata_server, after
  // possibly calling _publishCursor on multiple returned cursors.

  // register stop callback (expects lambda w/ no args).
  sub.onStop(function () {observeHandle.stop();});

  // return the observeHandle in case it needs to be stopped early
  return observeHandle;
};

它观察光标的变化,并在事情发生变化时调用订阅生命周期方法(转换为 DDP 突变消息)。我们在使用时将真实的集合名称替换为targetName

表示所有的结果都会发布到客户端的'temp'集合中,并且会与其他正常查询的数据分开发布到'real_collection_name'

【讨论】:

    猜你喜欢
    • 2021-07-18
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 2014-04-06
    相关资源
    最近更新 更多