【问题标题】:4 level subscription nesting in meteor4 级订阅嵌套在流星中
【发布时间】:2016-05-22 13:46:12
【问题描述】:

我正在使用流星,这是我的架构,每个都是一个单独的集合:

课程有很多讲座

讲座有很多问题

问题有很多答案

我想要 1 个页面,我可以在其中显示给定课程的讲座、问题和答案。我可以毫无问题地显示课程的讲座,但我在显示更多嵌套项目时遇到了问题。理想情况下,我希望拥有:

Lecture 有 courseId

Answer 有 LectureId(但没有 courseId)

问题有 answerId(但没有 LectureId 或 courseId)

这是明智的还是我应该在所有子组件中嵌入 courseIds 和 LectureIds?这是我的铁路由器,我试图扩展与嵌套讲座相同的想法,但我遇到了如何为订阅提供 LecturesId 的绊脚石:

Router.route('/courses/:_id', {
    name: 'CoursePage',
    waitOn: function(){
        return [
            Meteor.subscribe('singleCourse', this.params._id),
            Meteor.subscribe('lectures', this.params._id),
            Meteor.subscribe('questions', this.params._id)
        ];
    },
    data: function() {
        return Courses.findOne(this.params._id);
    }
});

这是课程页面的订阅,同样是我不知道如何输入 LectureId 的绊脚石:

Template.CoursePage.helpers({
    Lectures: function() {
        return Lectures.find({courseId: this._id});
    },
    Questions: function(lectureId) {
        return Questions.find({courseId: this._id, lectureId: lectureId});
    }
});

任何人都可以推荐一种为单个页面执行此 4 级嵌套的好方法吗?我认为我遗漏了一些明显的东西,但我无法通过谷歌搜索找到一个很好的例子。

谢谢!

【问题讨论】:

  • 使用smart-publish包怎么样?它可以帮助连接。

标签: meteor meteor-blaze


【解决方案1】:

你可以Publish Composite为此打包。请参阅以下示例代码并根据您的集合架构进行编辑,

Meteor.publishComposite('singleCourse', function (courseId) {
    return [{
        find: function() {
            return Courses.find({ id: courseId});
        }
    }, {
        find: function() {
            return Lectures.find({ courseId: courseId});
        },
        children: [{
            find: function(lecture) {
                return Questions.find({ lectureId: lecture.id });
            },
            children: [{
                find: function(question) {
                   return Answers.find({ questionId: question.id });
                }
            }]
        }}
    }]
});

然后在您的路由器中,您只需拨打一个订阅电话,

Router.route('/courses/:_id', {
    name: 'CoursePage',
    waitOn: function(){
        return [
            Meteor.subscribe('singleCourse', this.params._id)
        ];
    },
    data: function() {
        return Courses.findOne(this.params._id);
    }
});

这是迄今为止最好的包之一(如果不是最好的),可以响应式地发布来自不同集合的一组相关文档。

在进行此类反应式连接时存在一些已知问题,但对于较小的数据集,这没有任何问题。

希望对你有帮助。

【讨论】:

  • 这很好用,我可以看到带有 Questions.findOne() 的项目,非常感谢!最后一个问题,在 blaze 模板中,如果我说 {{#each Lectures}} 然后将 {{#each Questions}} 嵌套在其中,我如何将参数反馈给问题订阅?我试过 {{#each Questions LectureId = ../_id}} 没有成功。
  • 如果有帮助,您可以投票,如果它解决了您的问题,您可以接受它作为答案。 :)。对于您的其他问题,我不太确定,但您可以尝试{{#each Questions lectureId = _id}},因为您仍处于Lectures 数据上下文中。但正如我所说,我不太确定。 :)
【解决方案2】:

Mongo 可以支持使用聚合。 $lookup 将允许您在集合之间连接和收集数据,例如 SQL 连接。

在meteor 中使用它需要使用外部mongo($lookup 是Mongo 3.2 的新功能,meteor 的Mongo 仍然是2.6.7)和一个包如meteorhacks:aggregate 包。正如 cmets 中提到的,还有其他软件包可以解决这个问题,聚合正是我使用的;根据 mongo 聚合文档,您可以使用它调用 Courses.aggregate(...) 来生成您需要的数据。

在我的使用中,我定义了一个将过滤器参数作为参数的 Meteor 方法

'aggregateReport':function(filterPersonnel, filterCourse, filterQuarter){
return Personnel.aggregate([{$match: filterPersonnel}, {$unwind: "$courses"},
  {$lookup: {from: "courses", localField: "courses", foreignField: "_id", 
  as: "course_docs"}}, {$unwind: "$course_docs"}, {$match: filterCourse}, 
  {$match: filterQuarter}]);

人员有:国家、课程日期、姓氏、全名、...、课程编号、课程。 (省略号覆盖与查询无关)。上述根据过滤器查询人员,将其输出到每个课程的一条记录(这是程序中许多人的转录类型视图),然后将来自课程的信息作为course_docs 添加到返回的人员,然后过滤通过课程参数和日期参数。 代码和依赖项是流星 1.2; 2016 年 2 月

【讨论】:

  • 你能举个例子吗?