收藏、出版物和订阅是 Meteor 的一个棘手领域,文档可以更详细地讨论,以避免经常 混淆,有时会因混淆术语而被放大。
这是Sacha Greif(DiscoverMeteor 的合著者)在一张幻灯片中解释了出版物和订阅:
要正确理解为什么需要find()
多次调用,您需要了解 Meteor 中的集合、发布和订阅是如何工作的:
您在 MongoDB 中定义集合。还没有涉及流星。这些集合包含数据库记录(也称为“文件”并举蒙戈和流星,而是一个“文档”是不是数据库记录更普遍的;例如,更新规范或查询选择的文件太多- JavaScript对象包含field: value
对)。
然后定义集合 流星服务器上使用
MyCollection = new Mongo.Collection('collection-name-in-mongo')
这些集合包含来自 MongoDB 集合的所有数据,您可以MyCollection.find({...})
对它们运行,这将返回一个游标(一组记录,带有遍历它们并返回它们的方法)。
该游标(大部分时间)用于发布(发送)一组记录(称为“记录集”)。您可以选择仅发布这些记录中的某些字段。客户订阅的是记录集(而不是集合)。发布是由发布函数完成的,每次新客户端订阅时都会调用该函数,该函数可以使用参数来管理要返回的记录(例如,用户 ID,仅返回该用户的文档)。
在客户端,您有Minimongo集合,它们部分地反映了来自服务器的一些记录。“部分”是因为它们可能只包含部分字段,而“部分记录”是因为您通常只想将其需要的记录发送给客户端,以加快页面加载速度,并且只向客户端发送它需要并有权限的记录使用权。
Minimongo 本质上是纯 JavaScript 中 Mongo 的内存中非持久实现。它充当本地缓存,仅存储该客户端正在使用的数据库的子集。客户端上的查询(查找)直接从该缓存中提供服务,无需与服务器交谈。
这些 Minimongo 集合最初是空的。他们充满了
Meteor.subscribe('record-set-name')
调用。请注意,要订阅的参数不是集合名称;它是服务器在调用中使用的记录集的名称publish
。该subscribe()
调用将客户端订阅到一个记录集——来自服务器集合的一个记录子集(例如最近的 100 篇博客文章),每个记录中包含所有或一部分字段(例如,只有title
和date
)。Minimongo 如何知道将传入的记录放入哪个集合?集合的名称将是collection
发布处理程序的added
、changed
和removed
回调中使用的参数,或者如果缺少这些参数(大多数情况下都是这种情况),它将是服务器上 MongoDB 集合的名称。
修改记录
这就是 Meteor 使事情变得非常方便的地方:当您在客户端修改 Minimongo 集合中的记录(文档)时,Meteor 将立即更新所有依赖它的模板,并将更改发送回服务器,服务器反过来将更改存储在 MongoDB 中,并将它们发送给订阅了包含该文档的记录集的相应客户端。这称为延迟补偿,是Meteor的七项核心原则之一。
多个订阅
您可以有一堆订阅来获取不同的记录,但是如果它们来自服务器上的同一个集合,则它们最终都会在客户端上的同一个集合中,基于它们的_id
. 这没有解释清楚,但由 Meteor 文档暗示:
当您订阅记录集时,它会告诉服务器向客户端发送记录。客户端存储这些记录在本地Minimongo集合,具有相同的名称作为collection
中使用参数发布处理的added
,changed
和removed
回调。Meteor 将对传入的属性进行排队,直到您使用匹配的集合名称在客户端上声明 Mongo.Collection。
没有解释的是当您根本不显式使用added
, changed
and removed
, 或发布处理程序时会发生什么- 这是大多数情况下。在这种最常见的情况下,集合参数(不出所料)取自您在第 1 步在服务器上声明的 MongoDB 集合的名称。但这意味着您可以拥有不同名称的不同发布和订阅,以及所有记录将最终出现在客户端的同一个集合中。向下到顶级字段级别,Meteor 负责在文档之间执行集合联合,以便订阅可以重叠 - 发布将不同顶级字段发送到客户端的功能并排工作,并且在客户端上,集合将是两组字段的并集。
示例:在客户端填充相同集合的多个订阅
你有一个 BlogPosts 集合,你在服务器和客户端上以相同的方式声明它,即使它做不同的事情:
BlogPosts = new Mongo.Collection('posts');
在客户端,BlogPosts
可以从以下位置获取记录:
订阅最近的 10 篇博文
// server
Meteor.publish('posts-recent', function publishFunction() {
return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
}
// client
Meteor.subscribe('posts-recent');
订阅当前用户的帖子
// server
Meteor.publish('posts-current-user', function publishFunction() {
return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
// this.userId is provided by Meteor - http://docs.meteor.com/#publish_userId
}
Meteor.publish('posts-by-user', function publishFunction(who) {
return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
}
// client
Meteor.subscribe('posts-current-user');
Meteor.subscribe('posts-by-user', someUser);
订阅最受欢迎的帖子
- 等等。
所有这些文档都来自posts
MongoDB 中的集合,通过BlogPosts
服务器上的集合,最终在BlogPosts
客户端的集合中。
现在我们可以理解为什么您需要find()
多次调用了——第二次是在客户端上,因为来自所有订阅的文档最终会在同一个集合中,并且您只需要获取您关心的那些。例如,要获取客户端上的最新帖子,您只需从服务器镜像查询:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
这将返回一个光标,指向客户迄今为止收到的所有文档/记录,包括热门帖子和用户的帖子。(感谢杰弗里)。