Sammlungen, Veröffentlichungen und Abonnements sind ein schwieriger Bereich von Meteor, auf den in der Dokumentation näher eingegangen werden könnte, um häufige Verwirrung zu vermeiden , die manchmal durch verwirrende Terminologie verstärkt wird .
Hier erklärt Sacha Greif (Co-Autor von DiscoverMeteor ) Veröffentlichungen und Abonnements auf einer Folie:
Um zu verstehen, warum Sie find()
mehrmals anrufen müssen, müssen Sie wissen, wie Sammlungen, Veröffentlichungen und Abonnements in Meteor funktionieren:
Sie definieren Sammlungen in MongoDB. Noch kein Meteor beteiligt. Diese Sammlungen enthalten Datenbankeinträge (auch als „Dokumente“ sowohl von Mongo und Meteor , sondern ein „Dokument“ ist allgemeiner als eine Datenbank - Datensatz, zum Beispiel, eine Update - Spezifikation oder eine Abfrage Wähler sind Dokumente zu - JavaScript - Objekte enthalten field: value
Paare).
Anschließend definieren Sie Sammlungen auf dem Meteor-Server mit
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Diese Sammlungen enthalten alle Daten aus den MongoDB-Sammlungen, und Sie können sie ausführen MyCollection.find({...})
, wodurch ein Cursor zurückgegeben wird (eine Reihe von Datensätzen mit Methoden zum Durchlaufen und Zurückgeben).
Dieser Cursor wird (meistens) zum Veröffentlichen (Senden) einer Reihe von Datensätzen (als "Datensatzgruppe" bezeichnet ) verwendet. Sie können optional nur einige Felder aus diesen Datensätzen veröffentlichen. Es sind Datensatzgruppen ( keine Sammlungen), die Clients abonnieren . Die Veröffentlichung erfolgt über eine Veröffentlichungsfunktion , die jedes Mal aufgerufen wird, wenn ein neuer Client abonniert, und die Parameter verwenden kann, um zu verwalten, welche Datensätze zurückgegeben werden sollen (z. B. eine Benutzer-ID, um nur die Dokumente dieses Benutzers zurückzugeben).
Auf dem Client haben Sie Minimongo Sammlungen , die teilweise spiegeln einige der Datensätze vom Server. "Teilweise", weil sie möglicherweise nur einige der Felder enthalten, und "einige der Datensätze", weil Sie normalerweise nur die benötigten Datensätze an den Client senden möchten, um das Laden der Seite zu beschleunigen, und nur die Datensätze, die er benötigt und für die er die Berechtigung hat Zugriff.
Minimongo ist im Wesentlichen eine speicherinterne, nicht persistente Implementierung von Mongo in reinem JavaScript. Es dient als lokaler Cache, in dem nur die Teilmenge der Datenbank gespeichert wird, mit der dieser Client arbeitet. Abfragen auf dem Client (find) werden direkt aus diesem Cache heraus bereitgestellt, ohne mit dem Server zu sprechen.
Diese Minimongo-Sammlungen sind zunächst leer. Sie sind gefüllt mit
Meteor.subscribe('record-set-name')
Anrufe. Beachten Sie, dass der zu abonnierende Parameter kein Sammlungsname ist. Dies ist der Name eines Datensatzes , den der Server im publish
Aufruf verwendet hat. Der subscribe()
Aufruf abonniert den Client für einen Datensatz - eine Teilmenge von Datensätzen aus der Serversammlung (z. B. die letzten 100 Blog-Beiträge) mit allen oder einer Teilmenge der Felder in jedem Datensatz (z . B. nur title
und date
). Woher weiß Minimongo, in welche Sammlung die eingehenden Datensätze gestellt werden sollen? Der Name der Sammlung wird das sein collection
Argument in den veröffentlichen Handler verwendet added
, changed
und removed
Rückrufe, oder wenn letztere fehlen (was der Fall die meiste Zeit ist), wird es der Name der MongoDB - Sammlung auf dem Server sein.
Datensätze ändern
Hier macht Meteor die Dinge sehr bequem: Wenn Sie einen Datensatz (ein Dokument) in der Minimongo-Sammlung auf dem Client ändern, aktualisiert Meteor sofort alle davon abhängigen Vorlagen und sendet die Änderungen an den Server zurück, der dies wiederum tut speichert die Änderungen in MongoDB und sendet sie an die entsprechenden Clients, die einen Datensatz mit diesem Dokument abonniert haben. Dies wird als Latenzkompensation bezeichnet und ist eines der sieben Kernprinzipien von Meteor .
Mehrere Abonnements
Sie können eine Reihe von Abonnements haben, die unterschiedliche Datensätze abrufen, aber alle landen auf dem Client in derselben Sammlung, wenn sie auf der Grundlage ihrer Daten aus derselben Sammlung auf dem Server stammen _id
. Dies wird nicht klar erklärt, sondern durch die Meteor-Dokumente impliziert:
Wenn Sie einen Datensatz festlegen, wird der Server angewiesen, Datensätze an den Client zu senden. Der Client speichert diese Aufzeichnungen in lokalen Minimongo Sammlungen, mit dem gleichen Namen wie das collection
verwendete Argument in der Handler veröffentlichen added
, changed
und removed
Rückrufe. Meteor stellt eingehende Attribute in die Warteschlange, bis Sie die Mongo.Collection auf dem Client mit dem passenden Sammlungsnamen deklarieren.
Was nicht erklärt ist , was passiert , wenn Sie nicht tun explizit verwenden added
, changed
und removed
, oder veröffentlichen Handler überhaupt - die meiste Zeit ist. In diesem häufigsten Fall wird das Sammlungsargument (nicht überraschend) dem Namen der MongoDB-Sammlung entnommen, die Sie in Schritt 1 auf dem Server deklariert haben. Dies bedeutet jedoch, dass Sie unterschiedliche Veröffentlichungen und Abonnements mit unterschiedlichen Namen und alle Namen haben können Datensätze landen in derselben Sammlung auf dem Client. Bis auf die Ebene der Felder der obersten Ebene achtet Meteor darauf, eine festgelegte Vereinigung zwischen Dokumenten durchzuführen, sodass sich Abonnements überschneiden können. Veröffentlichen Sie Funktionen, die verschiedene Felder der obersten Ebene nebeneinander an den Client senden, und auf dem Client das Dokument im Sammlung wird die seinVereinigung der beiden Feldsätze .
Beispiel: Mehrere Abonnements füllen dieselbe Sammlung auf dem Client
Sie haben eine BlogPosts-Sammlung, die Sie sowohl auf dem Server als auch auf dem Client auf dieselbe Weise deklarieren, obwohl sie verschiedene Aktionen ausführt:
BlogPosts = new Mongo.Collection('posts');
Auf dem Client BlogPosts
können Datensätze abgerufen werden von:
ein Abonnement für die letzten 10 Blog-Beiträge
// server
Meteor.publish('posts-recent', function publishFunction() {
return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
}
// client
Meteor.subscribe('posts-recent');
ein Abonnement für die Beiträge des aktuellen Benutzers
// 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);
ein Abonnement für die beliebtesten Beiträge
- etc.
Alle diese Dokumente stammen aus der posts
Sammlung in MongoDB über die BlogPosts
Sammlung auf dem Server und landen in der BlogPosts
Sammlung auf dem Client.
Jetzt können wir verstehen, warum Sie find()
mehr als einmal anrufen müssen - das zweite Mal auf dem Client, da Dokumente aus allen Abonnements in derselben Sammlung landen und Sie nur diejenigen abrufen müssen, die Ihnen wichtig sind. Um beispielsweise die neuesten Beiträge auf dem Client abzurufen, spiegeln Sie einfach die Abfrage vom Server:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Dadurch wird ein Cursor auf alle Dokumente / Datensätze zurückgegeben, die der Kunde bisher erhalten hat, sowohl auf die Top-Beiträge als auch auf die Beiträge des Benutzers. ( Danke Geoffrey ).
BlogPosts.find({})
nach dem Abonnieren beider Veröffentlichungen auf dem Client etwas tun - dh es wird ein Cursor aller Dokumente / Datensätze zurückgegeben, die sich derzeit auf dem Client befinden, sowohl die Top-Beiträge als auch die Beiträge des Benutzers. Ich habe andere Fragen zu SO gesehen, bei denen der Fragesteller dadurch verwirrt war.