Meteor 组合订阅包 publish-composite 使用

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

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

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

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

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”,客户端只需按原来的方式订阅数据即可:

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

发表评论