Collecties, publicaties en abonnementen zijn een lastig gebied van Meteor, dat in de documentatie in meer detail zou kunnen worden besproken, om frequente verwarring te voorkomen, die soms wordt versterkt door verwarrende terminologie.
Hier is Sacha Greif (co-auteur van DiscoverMeteor) die publicaties en abonnementen in één dia uitlegt:
Om goed te begrijpen waarom je find()
. moet aanroepen meer dan eens, moet u begrijpen hoe collecties, publicaties en abonnementen werken in Meteor:
-
U definieert collecties in MongoDB. Er is nog geen Meteor bij betrokken. Deze collecties bevatten databaserecords (door zowel Mongo als Meteor ook wel "documenten" genoemd, maar een "document" is algemener dan een databaserecord; een updatespecificatie of een queryselector zijn bijvoorbeeld ook documenten - JavaScript-objecten die
field:value paren).
-
Vervolgens definieert u verzamelingen op de Meteor-server met
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Deze collecties bevatten alle de gegevens van de MongoDB-verzamelingen, en u kunt
MyCollection.find({...})
uitvoeren erop, die een cursor . teruggeeft (een set records, met methoden om ze te doorlopen en terug te sturen). -
Deze cursor wordt (meestal) gebruikt om publiceren (verzend) een set records (een "recordset" genoemd ). U kunt optioneel slechts sommige publiceren velden uit die records. Het zijn recordsets (niet collecties) die klanten abonneren tot. Publiceren wordt gedaan door een publicatiefunctie, die wordt aangeroepen telkens wanneer een nieuwe klant zich abonneert, en die parameters kan gebruiken om te beheren welke records moeten worden geretourneerd (bijv. een gebruikers-ID, om alleen de documenten van die gebruiker te retourneren).
-
Op de klant , je hebt Minimongo-collecties die gedeeltelijk spiegel sommige van de records van de server. "Gedeeltelijk" omdat ze slechts enkele van de velden kunnen bevatten en "sommige records" omdat u gewoonlijk alleen de records die hij nodig heeft naar de klant wilt sturen, om het laden van de pagina te versnellen, en alleen de records die hij nodig heeft en heeft toegangsrechten.
Minimongo is in wezen een in-memory, niet-persistente implementatie van Mongo in puur JavaScript. Het dient als een lokale cache die alleen de subset van de database opslaat waarmee deze client werkt. Query's op de client (zoeken) worden rechtstreeks vanuit deze cache geserveerd, zonder met de server te praten.
Deze Minimongo-collecties zijn in eerste instantie leeg. Ze worden ingevuld door
Meteor.subscribe('record-set-name')
belt. Merk op dat de te abonneren parameter geen collectienaam is; het is de naam van een recordset dat de server gebruikt in de
publish
telefoongesprek. Desubscribe()
call schrijft de klant in op een recordset - een subset van records uit de serververzameling (bijv. de meest recente 100 blogposts), met alle of een subset van de velden in elke record (bijv. alleentitel
endatum
). Hoe weet Minimongo in welke collectie de inkomende records moeten worden geplaatst? De naam van de collectie is decollectie
argument gebruikt intoegevoegd
. van de publicatie-handler ,gewijzigd
, enverwijderd
callbacks, of als deze ontbreken (wat meestal het geval is), is dit de naam van de MongoDB-verzameling op de server.
Records aanpassen
Dit is waar Meteor het erg handig maakt:wanneer u een record (document) in de Minimongo-verzameling op de client wijzigt, zal Meteor onmiddellijk alle sjablonen bijwerken die ervan afhankelijk zijn en de wijzigingen ook terugsturen naar de server, die op zijn beurt slaat de wijzigingen op in MongoDB en stuurt ze naar de juiste klanten die zich hebben geabonneerd op een recordset inclusief dat document. Dit heet latentiecompensatie en is een van de zeven kernprincipes van Meteor.
Meerdere abonnementen
Je kunt een heleboel abonnementen hebben die verschillende records binnenhalen, maar ze komen allemaal in dezelfde verzameling op de client terecht als ze uit dezelfde verzameling op de server komen, gebaseerd op hun _id
. Dit wordt niet duidelijk uitgelegd, maar geïmpliceerd door de Meteor-documenten:
Wanneer u zich abonneert op een recordset, vertelt het de server om records naar de client te verzenden. De klant slaat deze records op in lokale Minimongo-verzamelingen, met dezelfde naam als de
verzameling
argument gebruikt intoegevoegd
. van de publicatie-handler ,gewijzigd
, enverwijderd
terugbellen. Meteor zet binnenkomende attributen in de wachtrij totdat je de Mongo.Collection op de client declareert met de overeenkomende collectienaam.
Wat niet wordt uitgelegd, is wat er gebeurt als je niet gebruik expliciet toegevoegd
, gewijzigd
en verwijderd
, of publiceer handlers - wat meestal het geval is. In dit meest voorkomende geval is het verzamelingsargument (niet verwonderlijk) ontleend aan de naam van de MongoDB-verzameling die u bij stap 1 op de server hebt gedeclareerd. Maar wat dit betekent is dat u verschillende publicaties en abonnementen met verschillende namen kunt hebben, en alle records komen in dezelfde collectie op de klant terecht. Tot het niveau van velden op het hoogste niveau , Meteor zorgt voor een vaste unie tussen documenten, zodat abonnementen elkaar kunnen overlappen - publiceer functies die verschillende velden op het hoogste niveau naar de klant verzenden, werk zij aan zij en op de klant zal het document in de collectie de unie van de twee zijn reeksen velden.
Voorbeeld:meerdere abonnementen vullen dezelfde collectie op de client
Je hebt een verzameling BlogPosts, die je op dezelfde manier declareert op zowel de server als de client, ook al doet het verschillende dingen:
BlogPosts = new Mongo.Collection('posts');
Op de client, BlogPosts
kan records ophalen van:
-
een abonnement op de meest recente 10 blogberichten
// server Meteor.publish('posts-recent', function publishFunction() { return BlogPosts.find({}, {sort: {date: -1}, limit: 10}); } // client Meteor.subscribe('posts-recent');
-
een abonnement op de berichten van de huidige gebruiker
// 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);
-
een abonnement op de meest populaire berichten
- enz.
Al deze documenten komen uit de posts
verzameling in MongoDB, via de BlogPosts
verzamelen op de server, en eindigen in de BlogPosts
incasso op de klant.
Nu kunnen we begrijpen waarom je find()
. moet aanroepen meer dan eens - de tweede keer op de client, omdat documenten van alle abonnementen in dezelfde verzameling terechtkomen en u alleen diegene hoeft op te halen waar u om geeft. Om bijvoorbeeld de meest recente berichten op de client te krijgen, spiegelt u eenvoudig de vraag van de server:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Dit zal een cursor terugbrengen naar alle documenten/records die de klant tot nu toe heeft ontvangen, zowel de top posts als de posts van de gebruiker. (bedankt Geoffrey).