Колекції, публікації та підписки - це хитра область Метеора, яку в документації можна обговорити більш докладно, щоб уникнути частих плутанин , які іноді посилюються заплутаною термінологією .
Ось Саша Грейф (співавтор DiscoverMeteor ) пояснює публікації та підписки на одному слайді:
Щоб правильно зрозуміти, чому вам потрібно зателефонувати find()
більше одного разу, потрібно зрозуміти, як працюють колекції, публікації та підписки в Meteor:
Ви визначаєте колекції в MongoDB. Метеор ще не задіяний. Ці колекції містять запис бази даних (також звані «документи» на обох Монго і Метеор , але «документ» є більш загальним , ніж записи бази даних, наприклад, специфікація поновлення або селектор запиту документи теж - JavaScript об'єктів , що містять field: value
пари).
Потім ви визначаєте колекції на сервері Meteor за допомогою
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Ці колекції містять усі дані з колекцій MongoDB, і ви можете працювати MyCollection.find({...})
на них, що поверне курсор (набір записів із методами їх перебору та повернення).
Цей курсор (більшу частину часу) використовується для публікації (надсилання) набору записів (так званий "набір записів" ). За бажанням ви можете опублікувати лише деякі поля з цих записів. Клієнти передплачують саме набори записів (а не колекції) . Публікація здійснюється за допомогою функції публікації , яка викликається кожного разу, коли новий клієнт підписується, і яка може приймати параметри, щоб керувати тим, які записи повертати (наприклад, ідентифікатор користувача, щоб повернути лише документи цього користувача).
На клієнті у вас є колекції Minimongo, які частково відображають деякі записи із сервера. "Частково", оскільки вони можуть містити лише деякі поля, а "деякі записи", оскільки зазвичай ви хочете надіслати клієнту лише ті записи, які йому потрібні, щоб пришвидшити завантаження сторінки, і лише ті, які йому потрібні та має дозвіл на доступ.
Minimongo - це, по суті, непостійна реалізація Mongo в чистому JavaScript. Він служить локальним кешем, який зберігає лише підмножину бази даних, з якою працює цей клієнт. Запити на клієнті (find) подаються безпосередньо з цього кешу, не спілкуючись із сервером.
Ці колекції Minimongo спочатку порожні. Вони заповнені
Meteor.subscribe('record-set-name')
дзвінки. Зверніть увагу, що параметр для підписки не є назвою колекції; це ім'я набору записів, який сервер використовував у publish
дзвінку. subscribe()
Виклик виписує клієнт до набору записів - підмножина записів з колекції сервера (наприклад , останні 100 повідомлень в блозі), з усіма або підмножиною полів в кожному записі (наприклад , тільки title
і date
). Звідки Minimongo знає, до якої колекції розмістити вхідні записи? Назва колекції буде collection
аргумент , який використовується в публікують обробника added
, changed
і removed
зворотні виклики, або , якщо такі відсутні (що має місце в більшості випадків), то це буде назва колекції MongoDB на сервері.
Змінення записів
Тут Meteor робить речі дуже зручними: коли ви змінюєте запис (документ) у колекції Minimongo на клієнті, Meteor миттєво оновлює всі шаблони, які залежать від нього, а також відправляє зміни назад на сервер, який, у свою чергу збереже зміни в MongoDB і надішле їх відповідним клієнтам, які підписалися на набір записів, включаючи цей документ. Це називається компенсацією затримки і є одним із семи основних принципів Метеора .
Кілька підписок
Ви можете мати купу підписок, які збирають різні записи, але всі вони опиняться в одній колекції на клієнті, якщо надходять з тієї ж колекції на сервері, на основі їх _id
. Це не пояснюється чітко, але випливає з документів Meteor:
Коли ви підписуєтесь на набір записів, він повідомляє серверу надсилати записи клієнту. Клієнт зберігає ці записи в місцевих збірниках Minimongo, з тим же ім'ям, що і collection
аргумент використовується в опубліковувати обробник added
, changed
і removed
зворотні виклики. Meteor буде чергувати вхідні атрибути, доки ви не оголосите Mongo.Collection на клієнті з відповідним іменем колекції.
Що не пояснило , що відбувається , коли ви НЕ явно використовувати added
, changed
і removed
, або публікувати обробник взагалі - що велика частина часу. У цьому найпоширенішому випадку аргумент collection (як не дивно) береться з імені колекції MongoDB, яку ви оголосили на сервері на кроці 1. Але це означає, що ви можете мати різні публікації та підписки з різними іменами, і всі записи опиняться в тій же колекції на клієнті. До рівня полів верхнього рівня , Meteor піклується про те, щоб виконати набір об'єднань між документами, таким чином, щоб підписки могли перекриватися - публікувати функції, які доставляють різні поля верхнього рівня до роботи клієнта поруч і на клієнті, документ в колекція будеоб'єднання двох наборів полів .
Приклад: кілька підписок, що заповнюють одну і ту ж колекцію на клієнті
У вас є колекція BlogPosts, яку ви заявляєте однаково як на сервері, так і на клієнті, хоча вона робить різні речі:
BlogPosts = new Mongo.Collection('posts');
Клієнт BlogPosts
може отримати записи від:
передплата на останні 10 публікацій у блозі
Meteor.publish('posts-recent', function publishFunction() {
return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
}
Meteor.subscribe('posts-recent');
передплата на повідомлення поточного користувача
Meteor.publish('posts-current-user', function publishFunction() {
return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
}
Meteor.publish('posts-by-user', function publishFunction(who) {
return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
}
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});
Це поверне курсор до всіх документів / записів, які клієнт отримав дотепер, як верхніх повідомлень, так і публікацій користувача. ( спасибі Джеффрі ).
BlogPosts.find({})
на клієнті після підписки на обидві публікації, тобто він повертає курсор усіх документів / записів, що перебувають на даний момент у клієнта, як верхніх повідомлень, так і публікацій користувача. Я бачив інші запитання щодо SO, де запитувача це бентежило.