Samlinger, publikationer og abonnementer er et vanskeligt område af Meteor, som dokumentationen kunne diskutere mere detaljeret for at undgå hyppig forvirring, som nogle gange bliver forstærket af forvirrende terminologi.
Her er Sacha Greif (medforfatter til DiscoverMeteor), der forklarer publikationer og abonnementer på ét dias:
For at forstå, hvorfor du skal kalde find()
mere end én gang skal du forstå, hvordan samlinger, publikationer og abonnementer fungerer i Meteor:
-
Du definerer samlinger i MongoDB. Ingen Meteor involveret endnu. Disse samlinger indeholder databaseposter (også kaldet "dokumenter" af både Mongo og Meteor, men et "dokument" er mere generelt end en databasepost; for eksempel er en opdateringsspecifikation eller en forespørgselsvælger også dokumenter - JavaScript-objekter, der indeholder
field:value par).
-
Derefter definerer du samlinger på Meteor-serveren med
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Disse samlinger indeholder alle dataene fra MongoDB-samlingerne, og du kan køre
MyCollection.find({...})
på dem, hvilket vil returnere en markør (et sæt poster med metoder til at gentage dem og returnere dem). -
Denne markør bruges (det meste af tiden) til at udgive (send) et sæt poster (kaldet et "rekordsæt" ). Du kan valgfrit kun udgive nogle felter fra disse poster. Det er rekordsæt (ikke samlinger), som kunder abonnerer på til. Publicering udføres af en publiceringsfunktion, som kaldes hver gang en ny klient abonnerer, og som kan tage parametre til at styre, hvilke poster der skal returneres (f.eks. et bruger-id, for kun at returnere denne brugers dokumenter).
-
På klienten , du har Minimongo-samlinger, der delvis spejle nogle af posterne fra serveren. "Delvis", fordi de muligvis kun indeholder nogle af felterne, og "nogle af posterne", fordi du normalt kun ønsker at sende til klienten de poster, den har brug for, for at fremskynde sideindlæsningen, og kun dem, den har brug for og har adgangstilladelse.
Minimongo er i bund og grund en in-memory, ikke-vedvarende implementering af Mongo i ren JavaScript. Den fungerer som en lokal cache, der kun gemmer den delmængde af databasen, som denne klient arbejder med. Forespørgsler på klienten (find) serveres direkte fra denne cache uden at tale med serveren.
Disse Minimongo-samlinger er i første omgang tomme. De er udfyldt af
Meteor.subscribe('record-set-name')
opkald. Bemærk, at parameteren for at abonnere ikke er et samlingsnavn; det er navnet på et rekordsæt at serveren brugt i
publicer
opkald.subscribe()
call abonnerer klienten på et rekordsæt - et undersæt af poster fra serversamlingen (f.eks. de seneste 100 blogindlæg), med alle eller en undergruppe af felterne i hver post (f.eks. kuntitle
ogdato
). Hvordan ved Minimongo i hvilken samling de indkommende poster skal placeres? Navnet på samlingen vil væresamlingen
argument brugt i publiceringshandlerensadded
,ændret
, ogfjernet
tilbagekald, eller hvis disse mangler (hvilket er tilfældet det meste af tiden), vil det være navnet på MongoDB-samlingen på serveren.
Ændring af poster
Det er her, Meteor gør tingene meget praktiske:Når du ændrer en post (dokument) i Minimongo-samlingen på klienten, vil Meteor øjeblikkeligt opdatere alle skabeloner, der er afhængige af den, og vil også sende ændringerne tilbage til serveren, som igen gemmer ændringerne i MongoDB og sender dem til de relevante klienter, der har abonneret på et rekordsæt inklusive det pågældende dokument. Dette kaldes forsinkelseskompensation og er et af de syv kerneprincipper i Meteor.
Flere abonnementer
Du kan have en masse abonnementer, der trækker forskellige poster ind, men de ender alle i den samme samling på klienten, hvis de kom fra den samme samling på serveren, baseret på deres _id
. Dette er ikke forklaret klart, men underforstået af Meteor-dokumenterne:
Når du abonnerer på et rekordsæt, fortæller det serveren om at sende poster til klienten. Klienten gemmer disse poster i lokale Minimongo-samlinger med samme navn som samlingen
argument brugt i publiceringshandlerens added
, ændret
, og fjernet
tilbagekald. Meteor sætter indgående attributter i kø, indtil du erklærer Mongo.Collection på klienten med det matchende samlingsnavn.
Det, der ikke er forklaret, er, hvad der sker, når du ikke brug eksplicit added
, ændret
og fjernet
, eller publicere handlere i det hele taget - hvilket er det meste af tiden. I dette mest almindelige tilfælde er indsamlingsargumentet (ikke overraskende) taget fra navnet på den MongoDB-samling, du deklarerede på serveren i trin 1. Men det betyder, at du kan have forskellige publikationer og abonnementer med forskellige navne, og alle de poster vil ende i samme samling på klienten. Ned til niveauet for felter på øverste niveau , Meteor sørger for at udføre en fast forening mellem dokumenter, således at abonnementer kan overlappe - publicer funktioner, der sender forskellige topniveau felter til klienten arbejde side om side og på klienten, vil dokumentet i samlingen være foreningen af de to sæt af felter.
Eksempel:flere abonnementer, der udfylder den samme samling på klienten
Du har en BlogPosts-samling, som du erklærer på samme måde på både serveren og klienten, selvom den gør forskellige ting:
BlogPosts = new Mongo.Collection('posts');
På klienten, BlogPosts
kan hente optegnelser fra:
-
et abonnement på de seneste 10 blogindlæg
// server Meteor.publish('posts-recent', function publishFunction() { return BlogPosts.find({}, {sort: {date: -1}, limit: 10}); } // client Meteor.subscribe('posts-recent');
-
et abonnement på den aktuelle brugers indlæg
// 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);
-
et abonnement på de mest populære indlæg
- osv.
Alle disse dokumenter kommer fra indlæggene
samling i MongoDB via BlogPosts
samling på serveren og ender i BlogPosts
opkrævning på klienten.
Nu kan vi forstå, hvorfor du skal kalde find()
mere end én gang - anden gang på klienten, fordi dokumenter fra alle abonnementer ender i samme samling, og du skal kun hente dem, du holder af. For eksempel, for at få de seneste indlæg på klienten, spejler du blot forespørgslen fra serveren:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Dette vil returnere en markør til alle dokumenter/registreringer, som klienten har modtaget indtil videre, både de øverste indlæg og brugerens indlæg. (tak Geoffrey).