javascript - 了解 Meteor 发布/订阅

标签 javascript mongodb meteor publish-subscribe

我有一个简单的应用程序设置,显示 Projects 的列表.我已经删除了 autopublish打包,这样我就不会将所有内容都发送给客户。

 <template name="projectsIndex">    
   {{#each projects}}      
     {{name}}
   {{/each}}
 </template>

autopublish已打开,这将显示所有项目:
if Meteor.isClient
  Template.projectsIndex.projects = Projects.find()

删除它后,我还必须执行以下操作:
 if Meteor.isServer
   Meteor.publish "projects", ->
     Projects.find()
 if Meteor.isClient
   Meteor.subscribe "projects"
   Template.projectsIndex.projects = Projects.find()

那么,说客户端find()是否准确?方法只搜索从服务器端发布的记录?它一直让我绊倒,因为我觉得我应该只拨打 find()一次。

最佳答案

收藏、发布和订阅是 Meteor 的一个棘手的领域,文档可以更详细地讨论,以避免 frequent confusion ,有时会被 confusing terminology 放大.

这是Sacha Greif (DiscoverMeteor 的合著者)在一张幻灯片中解释出版物和订阅:

subscriptions

要正确理解为什么您需要调用 find()不止一次,您需要了解 Meteor 中的收藏、出版物和订阅是如何工作的:

  • 您在 MongoDB 中定义集合。还没有涉及 meteor 。这些集合包含 database records (Mongo and Meteor 也称为“文档”,但“文档”比数据库记录更通用;例如,更新规范或查询选择器是文档 too - JavaScript 对象包含 field: value 对) .
  • 然后你定义 collections在 meteor 服务器上

    MyCollection = new Mongo.Collection('collection-name-in-mongo')
    

    这些集合包含 全部 MongoDB 集合中的数据,您可以运行 MyCollection.find({...})在他们身上,这将返回一个 cursor (一组记录,带有遍历它们并返回它们的方法)。
  • 该游标(大部分时间)用于 publish (发送)一组记录(称为 “记录集” )。您可以选择仅发布 some这些记录中的字段。客户 是记录集(不是集合) subscribe 到。发布由 publish function 完成,每次新客户端订阅时都会调用它,并且可以使用参数来管理要返回的记录(例如,用户 ID,仅返回该用户的文档)。
  • 在客户端,您有 Minimongo部分镜像来自服务器的某些记录的集合。 “部分”是因为它们可能只包含部分字段,而“部分记录”是因为您通常只想将它需要的记录发送给客户端,以加快页面加载速度,并且只发送它需要并有权限的记录访问。

    Minimongo is essentially an in-memory, non-persistent implementation of Mongo in pure JavaScript. It serves as a local cache that stores just the subset of the database that this client is working with. Queries on the client (find) are served directly out of this cache, without talking to the server.



    这些 Minimongo 集合最初是空的。他们充满了

    Meteor.subscribe('record-set-name')
    

    调用。注意参数为subscribe不是集合名称;它是服务器在 publish 中使用的记录集的名称。打电话。 subscribe() call 将客户端订阅到记录集 - 服务器集合中的记录子集(例如最近的 100 篇博客文章),每个记录中包含所有字段或字段的子集(例如,只有 titledate )。 Minimongo 如何知道将传入的记录放入哪个集合?集合的名称将是 collection发布处理程序中使用的参数 added , changed , 和 removed回调,或者如果它们丢失(大多数情况下都是这种情况),它将是服务器上 MongoDB 集合的名称。

  • 修改记录

    这就是 Meteor 使事情变得非常方便的地方:当您在客户端修改 Minimongo 集合中的记录(文档)时,Meteor 将立即更新所有依赖它的模板,并将更改发送回服务器,服务器反过来将更改存储在 MongoDB 中,并将它们发送给订阅了包含该文档的记录集的相应客户端。这叫做延迟补偿并且是 seven core principles of Meteor 之一.

    多个订阅

    您可以有一堆订阅来获取不同的记录,但是如果它们来自服务器上的同一个集合,那么它们最终都会在客户端上的同一个集合中,基于它们的 _id .这没有解释清楚,但由 Meteor 文档暗示:

    When you subscribe to a record set, it tells the server to send records to the client. The client stores these records in local Minimongo collections, with the same name as the collection argument used in the publish handler's added, changed, and removed callbacks. Meteor will queue incoming attributes until you declare the Mongo.Collection on the client with the matching collection name.



    没有解释的是当你没有明确使用 added 时会发生什么, changedremoved , 或者根本不发布处理程序 - 大多数情况下是这样。在这种最常见的情况下,集合参数(不出所料)取自您在第 1 步在服务器上声明的 MongoDB 集合的名称。但这意味着您可以拥有不同名称的不同发布和订阅,以及所有记录将最终出现在客户端的同一个集合中。下降到的水平顶级字段 , Meteor 负责在文档之间执行集合并集,以便订阅可以重叠 - 发布将不同顶级字段发送到客户端的功能并排在客户端上工作,集合中的文档将是 union of the two sets of fields .

    示例:在客户端填充相同集合的多个订阅

    你有一个 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});
    

    这将返回一个光标,指向客户迄今为止收到的所有文档/记录,包括热门帖子和用户的帖子。 ( thanks Geoffrey )。

    关于javascript - 了解 Meteor 发布/订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19826804/

    相关文章:

    JavaScript 历史后退/前进

    java - Mongo Java 查询、DBRef 和一对多关系

    javascript - 如何使用 selectize.js 获取选定的 id 和文本值。 meteor ?

    javascript - fullcalendar 无法使用 meteor 正确渲染

    html - 在 Meteor 应用程序中放置苹果全屏元标记

    javascript - 如何使用 URL 在特定时间代码传递开始 HTML5 视频?

    javascript - 无法获取 SVG 样式 CSS

    mongodb - 带有 $date 的 mongo.input.query 不过滤输入到 hadoop

    mongodb - 查询 Mongodb 的文档,这些文档的子对象在关联数组中具有特定的 elem 值

    javascript - 如何将传单 map 嵌入到 Reveal.js 演示文稿中?