Ответ 1
Спасибо, что попросил меня написать более четкое объяснение. Вот более полный пример с моими комментариями. Было несколько ошибок и несоответствий, которые я очистил. Следующий выпуск docs будет использовать это.
Meteor.publish
довольно гибкий. Он не ограничивается публикацией существующих коллекций MongoDB клиенту: мы можем публиковать все, что захотим. В частности, Meteor.publish
определяет набор документов, на которые может подписаться клиент. Каждый документ принадлежит некоторому имени коллекции (строка), имеет уникальное поле _id
, а затем имеет некоторый набор атрибутов JSON. По мере изменения документов в наборе сервер отправит изменения каждому подписчиваемому клиенту, обновив клиент.
Мы собираемся определить здесь набор документов, называемый "counts-by-room"
, который содержит один документ в коллекции с именем "counts"
. Документ будет иметь два поля: a roomId
с идентификатором комнаты и count
: общее количество сообщений в этой комнате. Нет реальной коллекции MongoDB с именем counts
. Это просто имя коллекции, которую наш сервер Meteor будет отправлять клиенту, и хранить в клиентской коллекции с именем counts
.
Для этого наша функция публикации принимает параметр roomId
, который будет поступать от клиента, и наблюдает за запросом всех сообщений (определенных в другом месте) в этой комнате. Мы можем использовать более эффективную форму observeChanges
наблюдения запроса здесь, так как нам не нужен полный документ, просто знание о том, что новый был добавлен или удален. В любое время, когда добавляется новое сообщение с roomId
, которое нам интересно, наш обратный вызов увеличивает внутренний счетчик, а затем публикует новый документ клиенту с этим обновленным итогом. И когда сообщение удаляется, оно уменьшает счетчик и отправляет клиенту обновление.
Когда мы сначала вызываем observeChanges
, некоторое количество обратных вызовов added
будет запускаться сразу же, для каждого уже существующего сообщения. Затем будущие изменения будут срабатывать при каждом добавлении или удалении сообщений.
Наша функция публикации также регистрирует обработчик onStop
для очистки, когда клиент отписывает (либо вручную, либо отключается). Этот обработчик удаляет атрибуты от клиента и срывает запущенный observeChanges
.
Функция публикации запускается каждый раз, когда новый клиент подписывается на "counts-by-room"
, поэтому каждый клиент будет иметь observeChanges
от своего имени.
// server: publish the current size of a collection
Meteor.publish("counts-by-room", function (roomId) {
var self = this;
var count = 0;
var initializing = true;
var handle = Messages.find({room_id: roomId}).observeChanges({
added: function (doc, idx) {
count++;
if (!initializing)
self.changed("counts", roomId, {count: count}); // "counts" is the published collection name
},
removed: function (doc, idx) {
count--;
self.changed("counts", roomId, {count: count}); // same published collection, "counts"
}
// don't care about moved or changed
});
initializing = false;
// publish the initial count. `observeChanges` guaranteed not to return
// until the initial set of `added` callbacks have run, so the `count`
// variable is up to date.
self.added("counts", roomId, {count: count});
// and signal that the initial document set is now available on the client
self.ready();
// turn off observe when client unsubscribes
self.onStop(function () {
handle.stop();
});
});
Теперь, на клиенте, мы можем рассматривать это как обычную подписку на Meteor. Во-первых, нам нужен Mongo.Collection
, который будет содержать наш рассчитанный документ подсчета. Поскольку сервер публикует коллекцию с именем "counts"
, мы передаем "counts"
в качестве аргумента конструктору Mongo.Collection
.
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
Тогда мы можем подписаться. (Вы действительно можете подписаться перед объявлением коллекции: Meteor будет помещать входящие обновления в очередь, пока там не будет места для их размещения.) Имя подписки "counts-by-room"
, и оно принимает один аргумент: текущий идентификатор комнаты. Я обернул это внутри Deps.autorun
, чтобы при изменении Session.get('roomId')
клиент автоматически отменил подписку на счет старого номера комнаты и повторно отправил подписку на новый номер комнаты.
// client: autosubscribe to the count for the current room
Tracker.autorun(function () {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
Наконец, у нас есть документ в counts
, и мы можем использовать его так же, как и любую другую коллекцию Mongo на клиенте. Любой шаблон, который ссылается на эти данные, будет автоматически перерисовываться всякий раз, когда сервер отправляет новый счет.
// client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");