简体   繁体   English

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

[英]Creating a many to many relationship in a complex manner between 3 collections

I have 3 collections, meteor.user() , Categories and Posts . 我有3个收藏集, meteor.user()CategoriesPosts

A user can choose to follow any category's posts by saving the id of the category in an array in meteor.user() 用户可以通过将类别的ID保存在meteor.user()中的数组中来选择关注任何类别的帖子。

The end goal of this is that the user has a Personal stream where only the posts in the categories they are are following show up. 最终目的是使用户拥有一个“个人”流,其中显示他们正在关注的类别中的帖子。

Each post inside the Posts collection has within it an array of the Categories it's featured in. Posts collection每个Posts collection都包含一个以其为特色的Categories数组。

在此处输入图片说明

and each category has within it an array of posts, each post in the array has a field of ID of the post. 并且每个类别中都有一个帖子数组,该数组中的每个帖子都有一个帖子ID字段。

在此处输入图片说明

Where id: 67 is the id of the category, and posts.ID: 74 is the id of a post within the category. 其中id: 67是类别的ID,而posts.ID: 74是类别中的帖子的id。

below is the id of the post in Posts collection with matches posts.ID in the category collection 以下是帖子集合中帖子的ID,与类别集合中的匹配posts.ID

在此处输入图片说明

The User saves a category id so it appears as the category array in meteor.user() 用户保存类别ID,因此它在meteor.user()中显示为类别数组

在此处输入图片说明

When I do this 当我这样做时

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

I can do this 我可以做这个

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

But this lets me access the posts.ID within the category collection and display it. 但这使我可以访问类别集合中的posts.ID并显示它。

PROBLEM 问题

How can I go further and match posts.ID I got with the above code, to the the id of a post in Post so that I can access the posts from the Posts collection. 如何进一步匹配上面代码获得的posts.ID与Post中Post的ID,以便可以从Posts集合中访问Posts Could i do something like this? 我可以做这样的事情吗?

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);
  }
});

FURTHER EDIT AFTER ZIM ANSWER ZIM答案后的进一步编辑

So the solution you have given me is taking post.title from the post object contained within my Categories collection as shown below. 因此,您给我的解决方案是从我的Categories集合中包含的post对象获取post.title ,如下所示。

在此处输入图片说明

This post array within the Category collection is incomplete, its a copy of an original Posts Collection Category collectionpost数组不完整,它是原始Posts Collection的副本

what I need to do is use post.ID as shown in the image above. 我需要做的是使用上图所示的post.ID ie the post array within the Categories Collection, to create a many to many relationship with the id of a post within the original Posts Collection so, instead of having post.title I need to have title.rendered as below. 即类别集合中的帖子数组,以与原始Posts集合中的Posts id建立多对多关系 ,因此, post.title具有post.title我还需要具有title.rendered ,如下所示。

Posts Collection. 帖子集合。

在此处输入图片说明

If you see that the ID (not the top id, which is the id of the category), post.ID in the post array within the Categories collection is IDENTICAL to the id of the post in Posts collection. 如果您发现该ID (不是顶级的ID,这是该类别的ID), post.ID类别集合中的后阵列中是相同id在后的Posts集合。 This is the crux of it all, help me create a relationship so that, instead of displaying title or post.title from the post array within the Categories Collection, I need to display title.rendered within the original Posts Collection. 这就是全部的症结所在,可以帮助我建立一种关系,这样,我需要在原始的Posts集合中显示title.rendered ,而不是显示Categories集合中的post数组titlepost.title

it sounds like you don't control the data format, so you would have to use a nested loop to deal with the format you have. 听起来好像您无法控制数据格式,所以您必须使用嵌套循环来处理您拥有的格式。 i think the following should work. 我认为以下应该工作。

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

note i changed the name of your helper. 请注意,我更改了您的助手的名称。

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

cf http://blazejs.org/guide/spacebars.html#Each-in cf http://blazejs.org/guide/spacebars.html#Each-in

EDIT: 编辑:

ideally, you would be able to do a server-side join using a package like https://atmospherejs.com/reywood/publish-composite 理想情况下,您将能够使用https://atmospherejs.com/reywood/publish-composite之类的程序包进行服务器端连接

but since you don't have control over that, you can do a client-side join. 但由于您对此无能为力,因此可以进行客户端加入。 you would do this in the onCreated() of your template (caveat: this is untested!) 您可以在模板的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
        }
    });
});

then with a simple change to the template, you can grab those actual posts: 然后只需对模板进行简单的更改,就可以获取这些实际的帖子:

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

doing the client-side joins is a little more tricky, because as the above is written, you're missing reactivity to the user's tracked categories, and posts w/in the existing categories. 进行客户端联接比较棘手,因为撰写本文时,您缺少对用户跟踪类别的反应性,并且在现有类别中添加了帖子。 so you could further put all that in an autorun. 因此您可以将所有内容进一步放入自动运行中。 that would track changes to Meteor.user().category, but not sure if that would track post changes w/in the categories. 可以跟踪对Meteor.user()。category的更改,但不确定是否可以跟踪类别中的发布更改。 but this should get you a lot of the way there. 但这应该可以帮助您实现目标。

EDIT 2: 编辑2:

oh yeah, if you do it that way, that listener will stay active when the template goes away unless you call stop() on it. 哦,是的,如果这样做的话,除非您在模板上调用stop(),否则该侦听器将在模板消失时保持活动状态。 so... 所以...

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);
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM