根据另一个集合中特定文档的存在,将集合中的文档发布到流星客户端(发布与关系)

时间:2013-12-24 00:35:18

标签: meteor publish

我有两个收藏品

  1. 优惠(相关字段:_ id
  2. ShareRelations(相关字段: receiverId offerId
  3. 我想仅向已登录用户发布已分享给他的优惠。

    实际上,我是通过使用辅助数组(visibleOffers)来实现这一点的,我通过循环为每个ShareRelations填充,然后在Offers.find中使用此数组作为$ in选择器。

    我想知道这可能是流星方式这样做,还是我可以用更少和/或更漂亮的代码?

    我发布优惠的实际代码如下:

    Meteor.publish('offersShared', function () {
      // check if the user is logged in
      if (this.userId) {
        // initialize helper array
        var visibleOffers = [];
        // initialize all shareRelations which the actual user is the receiver
        var shareRelations = ShareRelations.find({receiverId: this.userId});
        // check if such relations exist
        if (shareRelations.count()) {
          // loop trough all shareRelations and push the offerId to the array if the value isn't in the array actually
          shareRelations.forEach(function (shareRelation) {
            if (visibleOffers.indexOf(shareRelation.offerId) === -1) {
              visibleOffers.push(shareRelation.offerId);
            }
          });
        }
        // return offers which contain the _id in the array visibleOffers
        return Offers.find({_id:  { $in: visibleOffers } });
      } else {
        // return no offers if the user is not logged in
        return Offers.find(null);
      }
    });
    

    此外,实际解决方案的缺点是,如果正在创建新的共享关系,客户端上的商品集合不会立即更新新显示的商品(阅读:需要页面重新加载。但我不是确定是否因为这种发布方法或某些其他代码而导致这种情况,因为这个问题不是主要问题。)

3 个答案:

答案 0 :(得分:9)

您正在寻找的是反应性加入。您可以通过直接在发布功能中使用observe来完成此操作,或者使用库来为您完成此操作。预计Meteor核心在某个时刻会有join library,但在此之前我建议使用publish-with-relations。看看文档,但我认为你想要的发布功能看起来像这样:

Meteor.publish('offersShared', function() {
  return Meteor.publishWithRelations({
    handle: this,
    collection: ShareRelations,
    filter: {receiverId: this.userId},
    mappings: [{collection: Offers, key: 'offerId'}]
  });
});

这应该被动地发布用户的所有ShareRelations以及所有关联的Offers。希望发布这两个不会有问题。

PWR是一个非常合法的软件包 - 我们中的一些人在生产中使用它,而Tom Coleman对它有所帮助。我唯一要提醒你的是,在撰写本文时,大气中的当前版本(v0.1.5)有一个错误,会导致相当严重的内存泄漏。在它受到影响之前,请参阅我的blog post,了解如何运行更新的本地副本。

更新2/5/14:

发现流星博客在reactive joins上有一篇很好的帖子,我强烈建议你阅读。

答案 1 :(得分:0)

这样做的方法是使用observeChanges()来解决这个问题。仍然试图弄清楚如何让这一切都适合我的例子,请参阅Meteor, One to Many Relationship & add field only to client side collection in Publish?

答案 2 :(得分:0)

您可以使用reactive-publish包(我是作者之一):

Meteor.publish('offersShared', function () {
  // check if the user is logged in
  if (this.userId) {
    this.autorun(function (computation) {
      // initialize helper array
      var visibleOffers = [];
      // initialize all shareRelations which the actual user is the receiver
      var shareRelations = ShareRelations.find({receiverId: this.userId}, {fields: {offerId: 1}});
      // loop trough all shareRelations and push the offerId to the array if the value isn't in the array actually
      shareRelations.forEach(function (shareRelation) {
        if (visibleOffers.indexOf(shareRelation.offerId) === -1) {
          visibleOffers.push(shareRelation.offerId);
        }
      });
      // return offers which contain the _id in the array visibleOffers
      return Offers.find({_id:  { $in: visibleOffers } });
    });
  } else {
    // return no offers if the user is not logged in
    return Offers.find(null);
  }
});

您可以将现有的非反应性代码简单地包装到autorun中,然后它就会开始工作。请注意确切查询哪些字段,因为如果您查询所有字段,则autorun将重新运行ShareRelations的任何字段更改,而不仅仅是offerId