初看这个标题可能有点晕,说的有点过于专业化,但是我也想不到更好的标题了。不过我们用真实的场景来给大家描述,来充分表达我们想表达的内容。熟悉使用 Meteor 发布(publish)和订阅(subcribe)的朋友可能会遇到这样一种情况。在某个列表页面,我们需要的数据分别储存在不同的集合(collection) 中。我们设计了一个查看某用户的所有评论的页面,按常规模式,我们首先可以根据用户的 ID 去评论的集合中查询该用户的所有评论内容,并根据该评论所关联的文章的 ID 查找到这篇文章的标题(Title)信息,用来显示在评论列表页提供用户查看或者访问。你可能会注意到,如果我们想获取到某条评论所关联的文章标题,我们必须要订阅这篇文章的内容,而在这之前我们并不知道这个用户都在哪些文章中有评论,若想订阅就需要把所有文章的结合订阅到客户端来使用,这样无疑是浪费资源和消耗时间的。

因此,组合订阅功能就油然而生了。它可以根据我们的需要,在一个 publish 中返回一组只符合我们需求的数据组合,组合中包含了我们所需的所有的信息,当我们首页需要显示某个用户所有的评论时,应该按如下步骤操作:

  • 首先在评论的集合中遍历该用户所有的评论内容
    • 遍历查询出来的评论集合中所有信息,根据每一条评论关联的文章 Id 查询文章数据
      • 查询该文章所有的点赞信息
      • 查询该文章的作者信息

这样操作后我们不会收到我们不关心的无关的数据,要实现上面的操作,首先你要安装 publish-composite 包,使用命令 meteor add reywood:publish-composite 即可添加,添加完成后我们来根据上面的需求组织以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Meteor.publishComposite("userCommentsComposite", function(userId) {
return {
find: function() {
// 根据用户 Id 查询出该用户所有的评论集合,注意这里是集合
return Comment.collection.find({userId: userId});
},
children: [
{
find: function(comment) {
// 遍历查询出来的评论集合中所有信息,根据每一条评论关联的文章 Id 查询文章数据
console.log("Get activityId by commantId : commandId =", comment._id, " commandLinkObjectId =", comment.linkedObjectId);
return Activities.find({_id: comment.linkedObjectId});
},
children: [
{
find: function(activity) {
// 查询该文章所有的点赞信息
console.log("Get like info by activityId :", activity._id);
return Like.collection.find({linkedObjectId: activity._id});
}
},
{
find: function(activity) {
// 查询该文章的作者信息
console.log("Get activity user info by activity.userId :", activity.userId);
return Meteor.users.find({_id: activity.userId});
}
}
]
}
]
}
});

请仔细查看以上代码的注释内容,完全是根据我们的需求一一发布了我们关心的数据,发布后的数据集合名字为 “userCommentsComposite”,客户端只需按原来的方式订阅数据即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
this.route('userComments', {
template: 'userComments',
path: '/user/:_id/comments/',
waitOn: function () {
Meteor.subscribe('images');
Meteor.subscribe('user', this.params._id);
return Meteor.subscribe('userCommentsComposite', this.params._id);
},
data: function() {
return {
comments: Comment.collection.find(),
activities: Activities.find(),
user: Meteor.users.findOne({_id: this.params._id}),
};
},
});

其中 userCommentsComposite 就是我们发布的数据,当我们访问这个路由下的页面时,我们可以根据我们输出的日志查看服务端获取数据的具体过程: 屏幕快照 2015-11-21 下午1.40.47 不出我们所料,服务端根据客户端传递过来的 userId 查询到了该用户所有的评论,这个用户有 4 条评论,随后根据每一条评论的 commandId 获取到了文章的信息,又根据文章的信息获取到了该文章的点赞数和作者等信息。这正是我们想要的。 以上就是一个完整的实例,如果大家还是没有理解或者希望得到更多信息,可以参考这个包的 github 和 atomsphere 地址: github:https://github.com/englue/meteor-publish-composite/ atomsphere:https://atmospherejs.com/reywood/publish-composite