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

Posted

技术标签:

【中文标题】在通过流星的发布方法提供数据之前从另一个 mongodb 集合中添加信息【英文标题】:Adding information from another mongodb collection before providing the data via meteor's publish method 【发布时间】:2014-11-08 06:14:23 【问题描述】:

我想在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,它会起作用。图像显示当前状态(自动发布 关闭)。如图所示,仅当当前用户与作者相同时才会显示作者的姓名。

--

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

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

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

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

非常感谢。

【问题讨论】:

【参考方案1】:

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

【讨论】:

明天试试,让你知道。谢谢!【参考方案2】:

您可以通过多种方式完成此连接。开始之前的几点说明:

正如我在回复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,这将无济于事。

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

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

您可以这样实现发布:

咖啡脚本

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];
);

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

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

优势

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

如果用户名发生变化,反应。

缺点

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

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

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

【讨论】:

感谢您的详细解答!我对 Coffeescript 不是很熟悉,但是我认为 Publish 方法必须返回一个游标。如果我使用你的代码,它不起作用,所以给我一个简短的提示;) 对此感到抱歉 - 我通常会尝试用与问题相同的方言给出答案。注意:1)coffeescript 具有隐式返回,因此我从发布函数返回一个数组,2)发布函数可以返回一个游标或游标数组。我提供的代码与第一个示例 javascript here 几乎相同,因此您可以将其用作指南。 Amir 比我更熟悉 coffeescript,但是我们都在努力理解这个问题。我不明白您如何返回游标(或列表或游标)。你见过路由器吗? github.com/Crowducate/crowducate.me/blob/master/client/router/… - 你的调整是否仍然正确? 我用发布功能的JS版本更新了答案。这有助于回答问题吗?这真的与您的路由器没有任何关系,因为我们仍在发布课程......我们也恰好也发布了一些用户。 waitOn 应该仍然有效。我不确定您的 data 部分发生了什么,但我不熟悉 minimongoid @DavidWeldon:这很有帮助。非常感谢您的时间。高度赞赏。

以上是关于在通过流星的发布方法提供数据之前从另一个 mongodb 集合中添加信息的主要内容,如果未能解决你的问题,请参考以下文章

Errno::EACCES:通过 gitlab 安装 gem 时权限被拒绝

流星 SSL 连接

如何使用铁路由器或流星本身提供文件?

为流星的 mongo 数据库设置密码

Rails在字段StripAttributes Gem之前和之后剥离空格

流星自动将地理位置保存到用户文档