Ответ 1
Коллекции, публикации и подписки являются сложной областью Метеор, что документация может обсуждаться более подробно, чтобы избежать частых которые иногда усиливаются запутанной терминологией.
Здесь Sacha Greif (соавтор DiscoverMeteor), объясняя публикации и подписки на одном слайде:
Чтобы правильно понять, почему вам нужно звонить find()
более одного раза, вам нужно понять, как работают коллекции, публикации и подписки в Meteor:
-
Вы определяете коллекции в MongoDB. Метеор еще не участвует. Эти коллекции содержат записи базы данных (также называемые "документами" как Mongo и Meteor, но "документ" более общий, чем запись базы данных, например, спецификация обновления или селектор запросов - это документы - объекты JavaScript, содержащие пары
field: value
). -
Затем вы определяете collections на сервере Meteor с помощью
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Эти коллекции содержат all данные из коллекций MongoDB, и вы можете запустить
MyCollection.find({...})
на них, что вернет cursor (набор записей, с помощью методов для их повторения и возврата их). -
Этот курсор (большую часть времени) используется для publish (отправить) набор записей (называемый "набором записей). Вы можете по желанию опубликовать только несколько полей из этих записей. Это набор записей (а не коллекции), в которых клиенты subscribe. Публикация выполняется публикация функции, которая вызывается каждый раз, когда клиент подписывается, и который может принимать параметры для управления возвращаемыми записями (например, идентификатор пользователя, чтобы возвращать только те пользовательские документы).
-
На клиенте у вас есть Minimongo коллекции, которые частично отражают некоторые записи с сервера. "Частично", потому что они могут содержать только некоторые из полей и "некоторые записи", потому что вы обычно хотите отправить клиенту только нужные ему записи, ускорить загрузку страницы и только те, которые ей нужны, и имеют разрешение на доступ.
Minimongo - это, по сути, встроенная в память, непостоянная реализация Mongo в чистом JavaScript. Он служит в качестве локального кеша, который хранит только подмножество базы данных, с которой работает этот клиент. Запросы на клиенте (поиск) подаются непосредственно из этого кеша, не разговаривая с сервером.
Эти коллекции Minimongo изначально пусты. Они заполнены
Meteor.subscribe('record-set-name')
вызовы. Обратите внимание, что параметр subscribe не является именем коллекции; это имя набора записей, которое сервер использовал в вызове
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
и removed
, или вообще не публикуете обработчики - это большая часть времени. В этом наиболее распространенном случае аргумент коллекции (неудивительно) берется из имени коллекции MongoDB, которую вы объявили на сервере на шаге 1. Но это означает, что вы можете иметь разные публикации и подписки с разными именами, а все записи будут попадать в одну коллекцию на клиенте. До уровня полей верхнего уровня 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});
Это вернет курсор ко всем документам/записям, которые клиент получил до сих пор, как к верхним сообщениям, так и к сообщениям пользователей. (благодарит Джеффри).