问题:在通过流星的发布方法提供数据之前从另一个 mongodb 集合中添加信息

我想在http://crowducate.me上完成什么:

  • 显示课程作者的用户名(即文档的“所有者”)。

当前代码:

Meteor.publish 'popularCourses', ->
# find all courses
  courses = Course.find({}, {sort: {createdAt: -1}}).fetch()
  for course in courses
# find each User by course owner
    owner = Meteor.users.findOne({_id: course.owner})
# overwrite the ownerId with the desired username
    course.owner = owner.username
  return courses

如果我打开_autopublish_,它会起作用。图像显示当前状态(自动发布_on_)。如图所示,仅当当前用户与作者相同时,才会呈现作者的姓名。

在此处输入图像描述

--

有朋友建议如下:https://gist.github.com/wiesson/1fd93d77ed9df353b7ab

“基本思想是在使用发布方法提供数据之前将用户名附加到课程。但是,如Meteor MongoDB 查找/获取问题中所述,发布方法应返回光标而不是对象数组。”

任何想法如何解决这个问题?将所有者用户名放入数组中?如果是这样,怎么做?

P.S.:源代码可以在这里找到(目前,比部署版本有更多的提交):https://github.com/Crowducate/crowducate.me

非常感谢。

解答

有几种方法可以完成此连接。在我们开始之前有几点注意事项:

  • 正如我在回答这个问题中解释的那样,发布功能中的排序对客户端上的文档顺序没有影响。

  • 在集合名称中使用复数形式是公认的标准。当集合包含课程时,Course看起来很奇怪。

  • 这个问题基本上是关于连接的,所以我建议阅读Reactive Joins In Meteor。

服务器改造

您的问题的字面答案是像这样转换服务器上的文档:

Meteor.publish 'popularCourses', ->
  transform = (fields) ->
    if fields.owner
      username = Meteor.users.findOne(fields.owner)?.username
      fields.owner = username
    fields

  handle = Course.find().observeChanges
    added: (id, fields) =>
      @added 'course', id, transform fields

    changed: (id, fields) =>
      @changed 'course', id, transform fields

    removed: (id) =>
      @removed 'course', id

  @ready()

  @onStop ->
    handle.stop()

优点

  • 所有工作都在服务器上完成,所以客户端可以像使用用户名一样使用owner

缺点

  • 使用observeChanges可能需要比简单连接更多的计算工作。

  • 如果您在其他地方发布课程,则很有可能在客户端合并文档时会覆盖owner。这可以通过附加一个像ownerUsername这样的字段来解决,但这也需要更昂贵的观察。

  • 如果您确实需要客户端某处的所有者 ID,这将无济于事。

  • 如果用户名发生变化,它不会反应(可能很少见,但我想我会指出这一点)。

非反应式发布+客户端加入

您可以像这样实现发布:

CoffeeScript

Meteor.publish 'popularCourses', ->
  courseCursor = Course.find()
  userIds = courseCursor.map (c) -> c.owner
  userCursor = Meteor.users.find {_id: $in: userIds}, {fields: username: 1}
  [courseCursor, userCursor]

JavaScript

Meteor.publish('popularCourses', function() {
  var courseCursor = Course.find();
  var userIds = courseCursor.map(function(c) {return c.owner;});
  var userCursor = Meteor.users.find(
    {_id: {$in: userIds}}, 
    {fields: {username: 1}
  });
  return [courseCursor, userCursor];
});

请注意,我小心地仅从userCursor发布username_id(您不想意外发布散列密码和会话数据)。然后你可以像这样加入客户端上的两个集合:

Template.myTemplate.helpers
  courses: ->
    Course.find().map (c) ->
      c.owner = Meteor.users.findOne(c.owner)?.username
      c

优势

  • 计算轻量级和简单的发布功能。

  • 如果用户名更改,则响应。

缺点

  • 如果所有者更改,则不响应。

  • 您需要在客户端上进行连接。一个有趣的替代方法是使用Collection Helpers之类的东西。

最后,我将指出您可以使用包来进行完全反应式连接。但是,除非所有者(或所有者的用户名)发生很大变化,否则这可能是矫枉过正。

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐