定义一个发布
发布需要定义在一个服务端文件中。例如,在示例应用Todos中,我们期望针对所有的用户发布公共清单的集合:
Meteor.publish('lists.public', function() {
return Lists.find({
userId: {$exists: false}
}, {
fields: Lists.publicFields
});
});
关于这端代码,有不少点需要去理解。首先我们用唯一字符Lists.public
命名了发布,我们也将在客户端使用这个名称使用它。其次,我们从发布的方法中简单地返回了一个Mongo游标(cursor)。注:游标被过滤以便仅返回集合中确定的字段,这在安全性相关的文章中有详细的介绍。
这意味着发布将简单地确保数据集匹配查询可有效地用于任何客户端的订阅。在当前这个示例中,所有的清单都没有设置userId
。所以当订阅打开时名为Lists
的客户端集合将具有在服务器集合Lists
中可用的所有公共清单。在Todos应用的这个特例中,订阅在应用启动时初始化且不会停止,而在稍后的章节中,我们将谈及订阅的生命周期。
每一个发布都有两种参数类型:
this
上下文,具有当前DDP连接的相关信息。例如,你可以使用this.userId
访问当前用户的_id
。- 发布的参数,它们可以在调用
Meteor.subscribe
时传递。
注:当我们需要访问
this
的上下文时,我们建议针对发布使用function() {}
而不是ES2015的语法() => {}
。你可以使用eslint-disable prefer-arrow-callboack
禁用箭头函数针对发布的检查规则。在未来版本的发布API将更好的与ES2015工作。
在当前发布中,当载入私有清单时,我们需要使用this.userId
获取属于特定用户的唯一todo清单。
Meteor.publish('lists.private', function() {
if (!this.userId) {
return this.ready();
}
return Lists.find({
userId: this.userId
}, {
fields: Lists.publicFields
});
});
感谢DDP协议及Meteor用户系统提供的保障,上述发布可以确信它将只会向用户发送属于他们的私人清单。需要注意的是,当用户登出时(或者又重新登录)发布将会重新执行,这意味着当当前用户变化时,发布私人清单的集合也将随之改变。
对于已登出用户的情况,我们明确地调用this.ready()
,用来表明我们打算发送的数据已经全部发送了(然而这个情况下并没有)。了解这些非常的重要,如果你没有返回一个发布的游标或者没有调用this.ready()
,那么用户的订阅将永远不会完成,然后他们将永远看到一个正加载的状态。
这里有一个发布的例子,传递了制定的参数。要注意的是检查通过网络传入参数的类型是非常重要的。
Meteor.publish('todos.inList', function(listId) {
// 我们需要检查`listId`是否是我们期望的类型
new SimpleSchema({
listId: {type: String}
}).validate({ listId });
// ...
});
当我们在客户端订阅这个发布时,经由Meteor.subscribe
的调用提供这个参数:
Meteor.subscribe('todos.inList', list._id);
组织发布
将发布放在它针对的特性边上,是非常有意义的。例如,某些时候发布提供非常详尽的数据但仅针对开发的视图有帮助。既然这样,把发布放在同一个模块或者视图代码的目录下是就再正常不过了。
然后通常发布是更为普遍的。举个例子,在示例应用Todos中,我们创建了一个名为todos.inList
的发布,它发布一个清单中的所有todo。尽管在应用中,我们只会在一处(在名为List_show
的模板中)使用它,在一个更大的应用中,很有可能我们需要在其他地方访问所有的清单中的todo。所以将发布放在todos
包中是一个非常明智的方法。