Sbírky, publikace a předplatné jsou záludnou oblastí Meteoru, kterou by dokumentace mohla probrat podrobněji, aby se předešlo častým nejasnostem, které jsou někdy umocněny matoucí terminologií.
Zde je Sacha Greif (spoluautor DiscoverMeteor), který vysvětluje publikace a předplatné na jednom snímku:
Abyste správně pochopili, proč musíte volat find()
více než jednou, musíte pochopit, jak sbírky, publikace a předplatné fungují v Meteoru:
-
Kolekce definujete v MongoDB. Zatím není zapojen žádný Meteor. Tyto kolekce obsahují záznamy databáze (Mongem i Meteorem nazývané také „dokumenty“, ale „dokument“ je obecnější než záznam databáze; například specifikace aktualizace nebo selektor dotazu jsou také dokumenty – objekty JavaScript obsahující
field:value páry).
-
Poté definujete kolekce na serveru Meteor s
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Tyto kolekce obsahují vše data z kolekcí MongoDB a můžete spustit
MyCollection.find({...})
na ně, což vrátí kurzor (soubor záznamů s metodami, jak je procházet a vracet). -
Tento kurzor se (většinou) používá k publikování (odeslat) sadu záznamů (nazývanou "sada záznamů" ). Volitelně můžete publikovat pouze některé pole z těchto záznamů. Jde o sady záznamů (ne kolekce), které si klienti přihlásí na. Publikování se provádí pomocí funkce publikování, která je volána pokaždé, když se nový klient přihlásí k odběru, a která může mít parametry pro správu, které záznamy se mají vrátit (např. ID uživatele, chcete-li vrátit pouze dokumenty tohoto uživatele).
-
U klienta , máte kolekce Minimongo, které částečně zrcadlit některé záznamů ze serveru. „Částečně“, protože mohou obsahovat jen některá z polí, a „některé ze záznamů“, protože obvykle chcete klientovi poslat jen ty záznamy, které potřebuje, pro urychlení načítání stránky a jen ty, které potřebujea má oprávnění k přístupu.
Minimongo je v podstatě neperzistentní implementace Mongo v čistém JavaScriptu v paměti. Slouží jako lokální mezipaměť, která ukládá pouze podmnožinu databáze, se kterou tento klient pracuje. Dotazy na klienta (najít) jsou obsluhovány přímo z této mezipaměti, bez komunikace se serverem.
Tyto kolekce Minimongo jsou zpočátku prázdné. Jsou vyplněny
Meteor.subscribe('record-set-name')
hovory. Všimněte si, že parametr pro přihlášení není název kolekce; je to název sady záznamů které server použil při
publikovat
volání.subscribe()
hovor přihlásí klienta k odběru sady záznamů – podmnožina záznamů z kolekce serveru (např. posledních 100 blogových příspěvků), se všemi nebo podmnožinou polí v každém záznamu (např. pouzetitle
adatum
). Jak Minimongo ví, do které sbírky má umístit příchozí záznamy? Název kolekce budekolekce
argument použitý v obslužné rutině publikovánípřidáno
,změněno
aodstraněno
zpětná volání, nebo pokud tato chybí (což je většinou případ), bude to název kolekce MongoDB na serveru.
Úprava záznamů
Zde je Meteor velmi pohodlný:když upravíte záznam (dokument) v kolekci Minimongo na klientovi, Meteor okamžitě aktualizuje všechny šablony, které na něm závisí, a také odešle změny zpět na server, který zase uloží změny v MongoDB a odešle je příslušným klientům, kteří si předplatili sadu záznamů obsahující daný dokument. Říká se tomu kompenzace latence a je jedním ze sedmi základních principů Meteoru.
Více odběrů
Můžete mít spoustu předplatných, která stahují různé záznamy, ale všechna skončí ve stejné sbírce na klientovi, pokud pocházejí ze stejné kolekce na serveru na základě jejich _id
. To není jasně vysvětleno, ale vyplývá z Meteor docs:
Když se přihlásíte k odběru sady záznamů, sdělí to serveru, aby poslal záznamy klientovi. Klient ukládá tyto záznamy do místních kolekcí Minimongo se stejným názvem jako
kolekce
argument použitý v obslužné rutině publikovánípřidáno
,změněno
aodstraněno
zpětná volání. Meteor bude řadit příchozí atributy do fronty, dokud nedeklarujete Mongo.Collection na klientovi s odpovídajícím názvem kolekce.
Není vysvětleno, co se stane, když to neděláte explicitně použijte přidáno
, změněno
a odstraněno
, nebo vůbec publikovat handlery – což je většinou. V tomto nejběžnějším případě je argument kolekce (nepřekvapivě) převzat z názvu kolekce MongoDB, kterou jste deklarovali na serveru v kroku 1. To však znamená, že můžete mít různé publikace a předplatná s různými názvy a všechny záznamy skončí ve stejné kolekci na klientovi. Až na úroveň polí nejvyšší úrovně , Meteor se stará o provedení sady mezi dokumenty, takže se předplatná mohou překrývat - publikovat funkce, které doručují různá pole nejvyšší úrovně do klientské práce vedle sebe a na klientovi, dokument v kolekci bude spojením těchto dvou sady polí.
Příklad:více předplatných vyplňujících stejnou sbírku na klientovi
Máte sbírku BlogPosts, kterou deklarujete stejným způsobem na serveru i na klientovi, i když dělá různé věci:
BlogPosts = new Mongo.Collection('posts');
Na klientovi BlogPosts
můžete získat záznamy z:
-
přihlášení k odběru posledních 10 blogových příspěvků
// server Meteor.publish('posts-recent', function publishFunction() { return BlogPosts.find({}, {sort: {date: -1}, limit: 10}); } // client Meteor.subscribe('posts-recent');
-
přihlášení k odběru příspěvků aktuálního uživatele
// 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);
-
předplatné nejoblíbenějších příspěvků
- atd.
Všechny tyto dokumenty pocházejí z příspěvků
sběr v MongoDB prostřednictvím BlogPosts
kolekce na serveru a skončí v BlogPosts
inkaso na klientovi.
Nyní chápeme, proč potřebujete volat find()
více než jednou – podruhé na klientovi, protože dokumenty ze všech předplatných skončí ve stejné sbírce a vy musíte načíst pouze ty, na kterých vám záleží. Chcete-li například získat nejnovější příspěvky na klientovi, jednoduše zrcadlíte dotaz ze serveru:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Tím se vrátí kurzor na všechny dokumenty/záznamy, které klient dosud obdržel, a to jak horní příspěvky, tak příspěvky uživatele. (díky Geoffreymu).