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


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

4 ответа:

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

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

subscriptions

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

то, что не объясняется, это то, что происходит, когда вы не явно использовать 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});

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

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

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

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

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

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

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


сервер

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

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

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

на стороне клиента .js file

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');