Понимание Meteor Публикация / Подписка

у меня есть простое приложение, которое показывает список 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() раз.

4 ответов


коллекции, публикации и подписки-сложная область Meteor, которую документация может обсудить более подробно, чтобы избежать часто путаница, которые иногда усиливаются путаешь терминологию.

здесь Саша Грейф (соавтор DiscoverMeteor) объяснение публикаций и подписок в одном слайде:

subscriptions

для правильно поймите, почему вам нужно позвонить find() более одного раза вам нужно понять, как работают коллекции, публикации и подписки в Meteor:

  1. вы определяете коллекции в MongoDB. Метеор пока не пострадал. Эти коллекции содержат записей базы данных (также называемый "документами" обоими Mongo Метеор, но "документ" является более общим, чем запись базы данных; например, спецификация обновления или селектор запросов-это документы слишком - объекты JavaScript, содержащие field: value пар).

  2. затем вы определяете коллекции на сервере Метеор с

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

    эти сборники содержат все данные из коллекций MongoDB, и вы можете запустить MyCollection.find({...}) на них, которые вернутсякурсор (набор записей с методами их итерации и вернуть их).

  3. этот курсор (большую часть времени) используется для публикации (отправить) набор записей (называется "рекорд"). Вы можете дополнительно опубликовать только некоторые полей этих записей. Это рекордные наборы (не коллекции), что клиенты подписаться to. Издание осуществляется публикации функция, который вызывается каждый раз, когда подписывается новый клиент, и который может принимать параметры для управления возвращаемыми записями (например, идентификатор пользователя, чтобы возвращать только документы этого пользователя).

  4. на клиенте, вы Minimongo коллекции частично зеркала некоторые записей с сервера. "Частично", потому что они могут содержать только некоторые поля, и "записи", потому что вы обычно хотите отправить клиенту нужны только записи, чтобы ускорить загрузку страницы, и только те, которые ему нужны и имеет разрешение на доступ.

    Minimongo по существу является в памяти, непостоянной реализацией Mongo в чистом JavaScript. Он служит локальным кэшем, в котором хранится только подмножество базы данных, с которой работает этот клиент. Запросы на клиенте (find) подаются непосредственно из этого кэша, не разговаривая с сервер.

    эти коллекции Minimongo изначально пусты. Они заполнены

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

    звонки. Обратите внимание, что параметр подписаться это не имя коллекции; это имя рекорд что сервер используется в publish звонок. The subscribe() вызов подписывается клиентом рекорд - подмножество записей из коллекции серверов (например, последние 100 сообщений в блоге), со всеми или подмножеством поля в каждой записи (например, только title и date). Как Minimongo знает, в какую коллекцию размещать входящие записи? Название коллекции будет collection аргумент, используемый в обработчике публикации added, changed и removed обратные вызовы, или если они отсутствуют (что происходит большую часть времени), это будет имя коллекции MongoDB на сервере.

изменение записи

это где Метеор делает вещи очень удобными: при изменении записи (документа) в коллекции Minimongo на клиенте Meteor мгновенно обновит все шаблоны, которые от него зависят, а также отправит изменения обратно на сервер, который в свою очередь сохранит изменения в MongoDB и отправит их соответствующим клиентам, подписавшимся на набор записей, включая этот документ. Это называется компенсации задержки и является одним из семь основных принципов Метеор.

несколько подписок

у вас может быть куча подписок, которые вытаскивают разные записи, но все они окажутся в одной коллекции на клиенте, если они пришли из одной коллекции на сервере, на основе их _id. Это не объясняется ясно, но подразумевается документами Meteor:

когда вы подписываетесь на набор записей, он сообщает серверу отправлять записи клиенту. Клиент хранит эти записи в местных коллекциях Minimongo, с тем же именем, что и collection аргумент, используемый в обработчике публикации added, changed и removed обратные вызовы. Meteor будет стоять в очереди входящих атрибутов, пока вы не объявите Монго.Коллекция на клиенте, с соответствующим именем коллекции.

что не объясняется, так это то, что происходит, когда вы не явно использовать added, changed и removed, или опубликовать обработчики вообще - что в большинстве случаев. В в этом наиболее распространенном случае аргумент collection (неудивительно) берется из имени коллекции MongoDB, объявленной на сервере на шаге 1. Но это означает, что у вас могут быть разные публикации и подписки с разными именами, и все записи окажутся в одной коллекции на клиенте. До уровня поля верхнего уровня, Meteor заботится о выполнении заданного объединения между документами, чтобы подписки могли перекрывать функции публикации это корабль различных полей верхнего уровня для работы клиента бок о бок и на клиенте, документ в коллекции будет объединение двух наборов полей.

пример: несколько подписок, заполняющих одну и ту же коллекцию на клиенте

у вас есть коллекция BlogPosts, которую вы объявляете одинаково как на сервере, так и на клиенте, хотя она делает разные вещи:

BlogPosts = new Mongo.Collection('posts');

на клиенте BlogPosts можно сделать записи:

  1. подписка на самые последние 10 сообщений в блоге

    // server
    Meteor.publish('posts-recent', function publishFunction() {
      return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
    }
    // client
    Meteor.subscribe('posts-recent');
    
  2. подписка на сообщения текущего пользователя

    // 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);
    
  3. подписка на самые популярные должности

  4. etc.

все эти документы исходят от posts коллекция в MongoDB, через BlogPosts коллекция на сервере, и в конечном итоге в BlogPosts коллекция на клиент.

теперь мы можем понять, почему нужно называть find() более одного раза-второй раз на клиенте, потому что документы из всех подписок окажутся в одной коллекции, и вам нужно будет получить только те, о которых вы заботитесь. Например, чтобы получить самые последние сообщения на клиенте, вы просто зеркально отражаете запрос с сервера:

var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});

это вернет курсор ко всем документам / записям, которые клиент получил до сих пор, как верхние сообщения и сообщения пользователя. (спасибо Джеффри).


да, клиентская сторона find () возвращает только документы, которые находятся на клиенте в Minimongo. От docs:

на клиенте создается экземпляр Minimongo. Minimongo по существу является в памяти, непостоянной реализацией Mongo в чистом JavaScript. Он служит локальным кэшем, в котором хранится только подмножество базы данных, с которой работает этот клиент. Запросы на клиенте (find) подаются непосредственно из этого кэша, не разговаривая с сервер.

Как вы говорите, publish () указывает, какие документы будут у клиента.


основное правило thumb здесь publish и subscribed имена переменных должны быть одинаковыми на стороне клиента и сервера.

имена коллекций на Mongo DB и на стороне клиента должны быть одинаковыми.

предположим, что я использую publish и subscribe для моей коллекции с именем employees тогда код будет выглядеть так


сервер

здесь использование var ключевое слово необязательно (используйте это ключевое слово, чтобы сделать коллекцию локальной для этого папка.)

CollectionNameOnServerSide = new Mongo.Collection('employees');   

Meteor.publish('employeesPubSub', function() { 
    return CollectionNameOnServerSide.find({});     
});

клиентской стороне .файл JS

CollectionNameOnClientSide = new Mongo.Collection('employees');
var employeesData = Meteor.subscribe('employeesPubSub');

Template.templateName.helpers({
  'subcribedDataNotAvailable' : function(){
        return !employeesData.ready();
    },
   'employeeNumbers' : () =>{
       CollectionNameOnClientSide.find({'empId':1});
  }
});

клиентской стороне .html файл

здесь мы можем использовать subcribedDataNotAvailable вспомогательный метод, чтобы узнать, готовы ли данные на стороне клиента, если данные готовы, то распечатайте номера сотрудников, используя employeeNumbers вспомогательный метод.

<TEMPLATE name="templateName">
{{#if subcribedDataNotAvailable}}
   <h1> data loading ... </h1>
 {{else}}
  {{#each employeeNumbers }}
     {{this}}
  {{/each}}
 {{/if}}
<TEMPLATE>

// on the server
Meteor.publish('posts', function() {

    return Posts.find();

});

// on the client
Meteor.subscribe('posts');