流星中的 4 层订阅嵌套

4 level subscription nesting in meteor

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

课程有很多讲

讲座有很多问题

问题有很多答案

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

讲座有 courseId

答案有 lectureId(但没有 courseId)

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

我应该在所有子组件中嵌入 courseId 和 lectureId 吗?这是我的铁路由器,我试图扩展与带问题的嵌套讲座相同的想法,但我遇到了如何为订阅提供讲座 ID 的绊脚石:

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 级嵌套的好方法吗?我认为我遗漏了一些明显的东西,但我无法通过 google 搜索找到一个很好的例子。

谢谢!

Mongo可以支持使用聚合。 $lookup 将允许您像 SQL 联接一样在集合之间连接和收集数据。

在 meteor 中使用它需要使用外部 mongo($lookup 是 Mongo 3.2 的新功能,meteor 的 Mongo 仍然是 2.6.7)和一个包,例如meteorhacks:aggregate 包。如评论中所述,还有其他解决此问题的软件包,聚合正是我所使用的;使用它,您可以根据 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}]);

人员有:国家、课程日期、姓氏、全名、...、课程编号、课程。 (省略号涵盖与查询无关的内容)。上面根据过滤器查询 Personnel,将其假脱机到每个课程的一条记录(这是程序中许多人的抄本视图类型),然后将 Courses 中的信息作为 course_docs 添加到返回的 Personnel,并且然后按课程参数和日期参数过滤。 代码和依赖项是 meteor 1.2; 2016 年 2 月

您可以 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);
    }
});

这是目前最好的包之一(如果不是最好的话),可以反应性地发布来自不同集合的一组相关文档。

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

希望对您有所帮助。