在通过流星的发布方法提供数据之前从另一个 mongodb 集合中添加信息
问题:在通过流星的发布方法提供数据之前从另一个 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之类的东西。
最后,我将指出您可以使用包来进行完全反应式连接。但是,除非所有者(或所有者的用户名)发生很大变化,否则这可能是矫枉过正。
更多推荐
所有评论(0)