在3个馆藏之间以复杂的方式创建多对多关系 [英] Creating a many to many relationship in a complex manner between 3 collections

查看:96
本文介绍了在3个馆藏之间以复杂的方式创建多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have 3 collections, meteor.user(), Categories and Posts.

用户可以通过将类别的ID保存在meteor.user()

A user can choose to follow any category's posts by saving the id of the category in an array in 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.

Posts collection中的每个帖子都在其中包含其精选类别的数组.

Each post inside the Posts collection has within it an array of the Categories it's featured in.

,并且每个类别中都有一个帖子数组,数组中的每个帖子都有帖子的ID字段.

and each category has within it an array of posts, each post in the array has a field of ID of the post.

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

Where id: 67 is the id of the category, and posts.ID: 74 is the id of a post within the category.

以下是帖子"集合中帖子的ID,与类别集合中的帖子相匹配.ID

below is the id of the post in Posts collection with matches posts.ID in the category collection

用户保存类别ID,因此它在meteor.user()中显示为类别数组

The User saves a category id so it appears as the category array in meteor.user()

当我这样做

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并显示它.

But this lets me access the posts.ID within the category collection and display it.

如何进一步匹配上面代码获得的posts.ID和Post中帖子的ID,以便可以访问Posts集合中的帖子.我可以做这样的事情吗?

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

在ZIM答案后进行进一步的编辑

因此,您给我的解决方案是从包含在我的Categories集合中的发布对象中获取post.title,如下所示.

FURTHER EDIT AFTER ZIM ANSWER

So the solution you have given me is taking post.title from the post object contained within my Categories collection as shown below.

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

This post array within the Category collection is incomplete, its a copy of an original Posts Collection

我需要做的是使用post.ID,如上图所示.即类别集合中的帖子数组,以与原始Posts集合中帖子的id创建多对多关系,因此,除了拥有post.title之外,我还需要拥有title.rendered如下.

what I need to do is use post.ID as shown in the image above. i.e. 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.

帖子集.

如果您看到ID(而不是顶部ID,即类别的ID),则Categories集合内的帖子数组中的post.ID IDENTICAL Posts集合中帖子的>.这就是全部的症结所在,请帮助我建立一种关系,这样,而不是显示Categories集合中的帖子数组 in 中的titlepost.title,我需要显示在原始Posts集合中.

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. 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.

推荐答案

听起来好像您无法控制数据格式,因此您必须使用嵌套循环来处理您拥有的格式.我认为以下方法应该有效.

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

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

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

ideally, you would be able to do a server-side join using a package like https://atmospherejs.com/reywood/publish-composite

但是由于您对此没有控制权,因此可以进行客户端连接.您可以在模板的onCreated()中执行此操作(注意:未经测试!)

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!)

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

进行客户端联接比较棘手,因为在撰写本文时,您缺少对用户跟踪类别的反应,并在现有类别中添加了帖子.因此您可以将所有内容进一步放入自动运行中.可以跟踪对Meteor.user().category的更改,但不确定是否可以跟踪类别中的发布更改.但这应该可以帮助您实现目标.

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. but this should get you a lot of the way there.

是的,如果您这样做的话,除非模板上调用stop(),否则该侦听器将在模板消失时保持活动状态.所以...

oh yeah, if you do it that way, that listener will stay active when the template goes away unless you call stop() on it. 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);
    });
});

这篇关于在3个馆藏之间以复杂的方式创建多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆