收藏,出版物和订阅是Meteor的一个棘手领域,文档可以进行更详细的讨论,以避免频繁的 混淆,有时混淆的术语会加剧混淆。
这是Sacha Greif(DiscoverMeteor的合著者)在一张幻灯片中解释了出版物和订阅:
为了正确理解为什么需要find()
多次调用的原因,需要了解集合,出版物和订阅在Meteor中的工作方式:
您在MongoDB中定义集合。尚未涉及流星。这些集合包含数据库记录(也称为“文件”并举蒙戈和流星,而是一个“文档”是不是数据库记录更普遍的;例如,更新规范或查询选择的文件太多- JavaScript对象包含field: value
对)。
然后定义集合 流星服务器上使用
MyCollection = new Mongo.Collection('collection-name-in-mongo')
这些集合包含MongoDB集合中的所有数据,您可以MyCollection.find({...})
在它们上运行,这将返回一个游标(一组记录,以及用于遍历它们并返回它们的方法)。
该游标(大部分时间)用于发布(发送)一组记录(称为“记录集”)。您可以选择仅发布那些记录中的某些字段。它是客户端订阅的记录集(而不是集合)。发布是通过publish函数完成的,每次新客户端订阅时都会调用该函数,并且该函数可以使用参数来管理要返回的记录(例如,用户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中,并将其发送给已订阅包含该文档的记录集的相应客户端。这称为延迟补偿,是流星的七个核心原理之一。
多个订阅
您可以有一堆订阅以获取不同的记录,但是如果订阅来自服务器上的相同集合(基于),则它们将全部位于客户端的相同集合中_id
。Meteor docs对此没有明确解释,但暗含了:
订阅记录集时,它告诉服务器将记录发送到客户端。客户端存储这些记录在本地Minimongo集合,具有相同的名称作为collection
中使用参数发布处理的added
,changed
和removed
回调。流星将对传入的属性进行排队,直到您在客户端上使用匹配的集合名称声明Mongo.Collection为止。
没有解释的是,当您根本不显式使用added
,changed
和removed
或完全不发布处理程序时会发生什么情况-通常是在大多数时候。在这种最常见的情况下,(毫无疑问)集合参数取自在步骤1在服务器上声明的MongoDB集合的名称。但这意味着您可以使用不同的名称拥有不同的发布和订阅,并且所有记录将最终存储在客户端的同一集合中。直到顶级字段的级别,Meteor都会在文档之间执行固定的并集,以使订阅可以重叠-发布将不同的顶级字段并排发送到客户端工作的功能,并在客户端上,将集合将是两套领域的联合。
示例:多个订阅填充客户端上的相同集合
您有一个BlogPosts集合,即使它做不同的事情,您也可以在服务器和客户端上以相同的方式声明它们:
BlogPosts = new Mongo.Collection('posts');
在客户端上,BlogPosts
可以从以下位置获取记录:
订阅最近的10篇博客文章
Meteor.publish('posts-recent', function publishFunction() {
return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
}
Meteor.subscribe('posts-recent');
订阅当前用户的帖子
Meteor.publish('posts-current-user', function publishFunction() {
return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
}
Meteor.publish('posts-by-user', function publishFunction(who) {
return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
}
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});
这将使光标返回到客户到目前为止已收到的所有文档/记录,包括最高职位和用户职位。(感谢Geoffrey)。
BlogPosts.find({})
在订阅了两个出版物之后在客户端上进行操作,即它将返回当前客户端上所有文档/记录的光标,包括顶部的帖子和用户的帖子。我在SO上看到过其他问题,问者对此感到困惑。