【问题标题】:Creating a many to many relationship in a complex manner between 3 collections在 3 个集合之间以复杂的方式创建多对多关系
【发布时间】:2017-11-03 20:54:21
【问题描述】:

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

用户可以通过将类别的id保存在meteor.user()的数组中来选择关注任何类别的帖子

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

Posts collection 中的每个帖子都包含一个包含其特色的类别的数组。

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

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

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

用户保存一个类别 id,因此它在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 并显示它。

问题

我怎样才能更进一步,将我使用上述代码获得的 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 回答后的进一步编辑

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

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

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

帖子集合。

如果您看到 ID(不是顶部 id,即类别的 id),则 Categories 集合中 post 数组中的 post.ID 与 @987654359 是 IDENTICAL @Posts 收藏中的帖子。这是这一切的症结所在,帮我建立一个关系,这样,我需要显示@987654364,而不是显示Categories集合中的帖子数组中的titlepost.title @在原Posts集合内。

【问题讨论】:

  • 我谦虚地建议您将整个架构放入不同的集合中。所有数据都会暴露在客户端,这是非常危险的。您宁愿制作各自的集合,然后制作一个公共字段来映射每个条目。你真的不需要让事情变得如此复杂,因为内部关系可以像这样解决 -> stackoverflow.com/questions/44203584/… 你可以在帮助程序和订阅的帮助下简单地在模板内循环数据。
  • 您好,感谢您的回复。 @AnkurSoni 这很复杂,我还没有定义模式,数据是通过 json 作为 WordPress 发布的。 Hense 为什么我要这样做。
  • 您的问题是什么? :)
  • 我怎样才能将类别集合中的posts.ID与其在Posts中的完全匹配(即帖子ID)匹配,而不是在模板中显示posts.ID,这样,而不是显示来自类别集合的帖子数据,我可以通过匹配 ID @AnkurSoni 显示来自帖子本身的数据
  • 我已经给你链接了。看看答案。它解释了你刚才问的一切。保持冷静,放松并阅读答案。我也曾经有过这个问题,解决方法很简单。

标签: javascript meteor meteor-collections


【解决方案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}}

参考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().category 的更改,但不确定是否会跟踪类别中的帖子更改。但这应该会让你走得很远。

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

【讨论】:

  • 感谢您抽出宝贵时间回复。请查看进一步的编辑以准确解释我的需要。长话短说,我已经成功获得了 post.title,但问题是它来自 Categories 集合中的 post 数组,而不是 Posts 集合。请查看编辑以获取更多解释@zim
  • @ShinaiMunyuki,明白了。我将通过客户端加入更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 1970-01-01
  • 2019-08-24
  • 2019-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多