Tack för att du fick mig att skriva en tydligare förklaring. Här är ett mer utförligt exempel med mina kommentarer. Det fanns några buggar och inkonsekvenser som jag har städat upp. Nästa dokumentversion kommer att använda detta.
Meteor.publish
är ganska flexibel. Det är inte begränsat till att publicera befintliga MongoDB-samlingar till kunden:vi kan publicera vad vi vill. Närmare bestämt Meteor.publish
definierar en uppsättning dokument som en kund kan prenumerera på. Varje dokument tillhör ett samlingsnamn (en sträng), har ett unikt _id
och har sedan en uppsättning JSON-attribut. När dokumenten i uppsättningen ändras kommer servern att skicka ändringarna ner till varje prenumererad klient, vilket håller klienten uppdaterad.
Vi kommer att definiera en dokumentuppsättning här, kallad "counts-by-room"
, som innehåller ett enda dokument i en samling som heter "counts"
. Dokumentet kommer att ha två fält:ett roomId
med ID för ett rum och count
:det totala antalet meddelanden i det rummet. Det finns ingen riktig MongoDB-samling som heter counts
. Detta är bara namnet på samlingen som vår Meteor-server kommer att skicka ner till klienten och lagra på en klientsida samling med namnet counts
.
För att göra detta tar vår publiceringsfunktion ett roomId
parameter som kommer från klienten och observerar en fråga av alla meddelanden (definierade på annat håll) i det rummet. Vi kan använda de mer effektiva observeChanges
form av att observera en fråga här eftersom vi inte behöver hela dokumentet, bara vetskapen om att en ny har lagts till eller tagits bort. När som helst ett nytt meddelande läggs till med roomId
vi är intresserade av, vår callback ökar det interna antalet och publicerar sedan ett nytt dokument till kunden med den uppdaterade summan. Och när ett meddelande tas bort minskar det antalet och skickar uppdateringen till klienten.
När vi först anropar observeChanges
, ett antal added
återuppringningar kommer att köras direkt, för varje meddelande som redan finns. Sedan kommer framtida ändringar att aktiveras när meddelanden läggs till eller tas bort.
Vår publiceringsfunktion registrerar även en onStop
hanterare för att städa upp när klienten avslutar prenumerationen (antingen manuellt eller vid frånkoppling). Den här hanteraren tar bort attributen från klienten och river ner de pågående observeChanges
.
En publiceringsfunktion körs varje gång en ny klient prenumererar på "counts-by-room"
, så varje klient kommer att ha en observeChanges
kör på dess vägnar.
// 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();
});
});
Nu, på klienten, kan vi behandla detta precis som ett typiskt Meteor-abonnemang. Först behöver vi en Mongo.Collection
som kommer att hålla vårt beräknade antal dokument. Eftersom servern publicerar i en samling som heter "counts"
, skickar vi "counts"
som argument till Mongo.Collection
konstruktör.
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
Då kan vi prenumerera. (Du kan faktiskt prenumerera innan du deklarerar samlingen:Meteor kommer att köa de inkommande uppdateringarna tills det finns en plats att placera dem.) Namnet på prenumerationen är "counts-by-room"
, och det krävs ett argument:det aktuella rummets ID. Jag har packat in det här i Deps.autorun
så att som Session.get('roomId')
ändringar kommer klienten automatiskt att avsluta prenumerationen från det gamla rummets antal och prenumerera på det nya rummets antal.
// client: autosubscribe to the count for the current room
Tracker.autorun(function () {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
Äntligen har vi dokumentet i Counts
och vi kan använda den precis som vilken annan Mongo-kollektion som helst på klienten. Alla mallar som refererar till denna data kommer automatiskt att ritas om när servern skickar en ny räkning.
// client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");