在通过meteor的发布方法提供数据之前,从另一个mongodb集合添加信息

时间:2014-09-14 17:12:39

标签: javascript arrays mongodb meteor coffeescript

我希望在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 ,它就可以了。图像显示当前状态(自动发布关闭)。如图所示,只有当前用户与作者相同时才会呈现作者姓名。

enter image description here

-

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

  

“基本的想法是在向数据提供发布方法之前将用户名附加到课程。但是,如Meteor MongoDB find / fetch issues中所述,发布方法应该返回一个光标而不是一个对象数组。”

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

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

非常感谢。

2 个答案:

答案 0 :(得分:3)

您可以通过多种方式完成此加入。在我们开始之前的几点说明:

  • 正如我在this question的答案中所解释的那样,在发布功能中排序不会影响客户端上的文档顺序。

  • 在集合名称中使用复数形式是可接受的标准。当集合包含课程时,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];
});

请注意,我要谨慎地仅发布username _iduserCursor(您不希望通过以下方式发布散列密码和会话数据事故)。然后你可以在客户端加入这两个集合,如下所示:

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

优点

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

  • 如果用户名更改,则为“无效”。

缺点

  • 如果所有者更改,则不会被动。

  • 您需要在客户端上进行加入。一个有趣的选择是使用Collection Helpers

  • 之类的东西

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

答案 1 :(得分:1)

一个简单的解决方案是只发布popularCoursesowners,并将所有者添加到客户端上的每个课程(使用您在出版物上编写的完全相同的代码)。