在3个集合之间以复杂的方式创建多对多关系

时间:2017-06-02 12:30:52

标签: javascript meteor meteor-collections

我有3个馆藏,meteor.user()CategoriesPosts

用户可以通过在meteor.user()

中的数组中保存类别的ID来选择关注任何类别的帖子

最终目标是用户拥有个人信息流,其中他们所关注的类别中的帖子会显示。

Posts collection内的每个帖子都包含一个其所属类别的数组。

enter image description here

并且每个类别都包含一系列帖子,数组中的每个帖子都有一个帖子的ID字段。

enter image description here

其中id: 67是该类别的ID,posts.ID: 74是该类别中帖子的ID。

下面是帖子集合中帖子的ID,其中匹配类别集合中的posts.ID

enter image description here

用户保存类别ID,使其在meteor.user()

中显示为类别数组

enter image description here

当我这样做时

Template.userTimeline.helpers({
  category: function() {
    var posts = Category.find({
      id: {
        $in: Meteor.user().category
      }
    });
    return posts
    console.log(posts);
  }
});

我可以这样做

 {{#each category}}
  <ul class="article-timeline">
    {{#each posts}} {{ID}} {{/each}}
  </ul>
{{/each}}

但是这可以让我访问类别集合中的posts.ID并显示它。

问题

如何进一步匹配posts.ID我将上述代码与Post中的帖子的ID相关联,以便我可以访问Posts集合中的帖子。我可以这样做吗?

Template.userTimeline.helpers({
  category: function() {
    var postsInCategory = Category.find({
      id: {
        $in: Meteor.user().category
      }
    });

    var postMatch = Post.find({
      ID: {
        $in: postsInCategory
      }
    });
    return postMatch
    console.log(postMatch);
  }
});

ZIM ANSWER之后的进一步编辑

所以你给我的解决方案是从{/ 1>}我的post.title集合中包含的帖子对象中获取Categories,如下所示。

enter image description here

post中的Category collection数组不完整,是原始Posts Collection的副本

我需要做的是使用post.ID,如上图所示。即类别集合中的帖子数组,用原始id集合中的帖子的Posts创建多对多关系,而不是{{1我需要post.title如下所示。

帖子收藏。

enter image description here

如果您看到title.rendered(不是顶级ID,即类别的ID),则“类别”集合中的帖子数组中的ID IDENTICAL post.ID集合中帖子的id。这是所有这一切的关键,帮助我创建一个关系,而不是在Posts集合中的帖子数组中显示titlepost.title,我需要在原始Categories集合中显示title.rendered

1 个答案:

答案 0 :(得分:1)

听起来你不能控制数据格式,所以你必须使用嵌套循环来处理你拥有的格式。我认为以下内容应该有效。

Template.userTimeline.helpers({
  categories: function() {
    return Category.find({
      id: {
        $in: Meteor.user().category
      }
    });
  }
});

注意我改变了帮助者的名字。

{{#each category in categories}}
  {{category.description}}
  {{#each post in category.posts}}
    {{post.title}}
  {{/each}}
{{/each}}

c.f。 http://blazejs.org/guide/spacebars.html#Each-in

编辑:

理想情况下,您可以使用https://atmospherejs.com/reywood/publish-composite

等软件包进行服务器端连接

但由于您无法控制,因此您可以进行客户端加入。你会在模板的onCreated()中这样做(警告:这是未经测试的!)

this.subscribe('posts', function() {
    let cursor = Categories.find({id: {$in: Meteor.user().category}});

    cursor.observe({
        added: function(newDocument) {
            let category = newDocument;

            // for this category, get all the associated post ids
            let postIds = _.map(category.posts, function(p)) {
                return p.ID;
            };

            // get the posts. we can fetch these because we waited for the publish of the posts collection.
            let actualPosts = Posts.find({id: {$in: postIds}}).fetch();

            // attach the actual posts to the category
            category.actualPosts = actualPosts;
        },
        changed: function(newDocument, oldDocument)  {
            // if wanting to track changes to the categories, similar to added block
        }
    });
});

然后只需对模板进行简单更改,就可以抓住这些实际帖子:

{{#each category in categories}}
  {{category.description}}
  {{#each post in category.actualPosts}}
    {{post.title}}
  {{/each}}
{{/each}}

进行客户端连接有点棘手,因为如上所述,您将缺少对用户跟踪类别的反应,以及现有类别中的帖子。所以你可以进一步把所有这些都放在自动运行中。这将跟踪Meteor.user()。类别的更改,但不确定是否会跟踪类别中的帖子更改。但这应该会让你在很多方面。

编辑2:

是的,如果你那样做,那么当模板消失时,该监听器将保持活动状态,除非你在它上面调用stop()。所以...

Template.userTimeline.onDestroyed(function() {
    let handle = this.observeHandle.get();

    if (handle) {
        handle.stop();
    }
});

Template.userTimeline.onCreated(function() {
    let self = this;
    self.observeHandle = new ReactiveVar();

    self.subscribe('posts', function() {
        let cursor = Categories.find({id: {$in: Meteor.user().category}});

        let handle = cursor.observe({
            added: function(newDocument) {
                let category = newDocument;

                // for this category, get all the associated post ids
                let postIds = _.map(category.posts, function(p)) {
                    return p.ID;
                };

                // get the posts
                let actualPosts = Posts.find({id: {$in: postIds}}).fetch();

                // attach the actual posts to the category
                category.actualPosts = actualPosts;
            },
            changed: function(newDocument, oldDocument)  {
                // if wanting to track changes, similar to added block
            }
        });

        self.observeHandle.set(handle);
    });
});