MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mungopopulation vs. Objektverschachtelung

Das erste, was Sie über die Mungopopulation wissen müssen, ist, dass es keine Zauberei ist, sondern nur eine bequeme Methode, mit der Sie zugehörige Informationen abrufen können, ohne alles selbst tun zu müssen.

Das Konzept ist im Wesentlichen für den Einsatz gedacht, wenn Sie entscheiden, dass Sie Daten in einer separaten Sammlung platzieren müssen, anstatt diese Daten einzubetten, und Ihre Hauptüberlegungen in der Regel auf der Dokumentgröße liegen sollten oder wenn diese zugehörigen Informationen häufig aktualisiert werden müssen Pflege eingebetteter Daten unhandlich.

Der „nicht magische“ Teil ist, dass im Wesentlichen, was unter der Decke passiert, ist, dass, wenn Sie eine andere Quelle „referenzieren“, die Füllfunktion eine zusätzliche Abfrage/Abfragen an diese „verwandte“ Sammlung durchführt, um diese Ergebnisse der übergeordneten Quelle „zusammenzuführen“. Objekt, das Sie abgerufen haben. Sie könnten dies selbst tun, aber die Methode dient der Bequemlichkeit, um die Aufgabe zu vereinfachen. Die offensichtliche Überlegung zur „Leistung“ besteht darin, dass es keinen einzigen Roundtrip zur Datenbank (MongoDB-Instanz) gibt, um alle Informationen abzurufen. Es gibt immer mehr als einen.

Nehmen Sie als Beispiel zwei Sammlungen:

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        ObjectId("5392fee10ff066b7d533a766"),
        ObjectId("5392fefe0ff066b7d533a767")
    ]
}

Und die Artikel:

{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }

Das „Beste“, was durch ein „referenziertes“ Modell oder die Verwendung von „Populate“ (unter der Haube) erreicht werden kann, ist Folgendes:

var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();

Es gibt also eindeutig "mindestens" zwei Abfragen und Operationen, um diese Daten zu "verbinden".

Das Einbettungskonzept ist im Wesentlichen die Antwort von MongoDB darauf, wie man damit umgeht, „Joins“ nicht zu unterstützen. Anstatt Daten in normalisierte Sammlungen aufzuteilen, versuchen Sie also, die "verwandten" Daten direkt in das Dokument einzubetten, das sie verwendet. Die Vorteile hier bestehen darin, dass es eine einzige „Lese“-Operation zum Abrufen der „zugehörigen“ Informationen und auch einen einzelnen Punkt von „Schreib“-Operationen gibt, um sowohl „übergeordnete“ als auch „untergeordnete“ Einträge zu aktualisieren, obwohl oft nicht möglich ist, in sie zu schreiben "viele" Kinder auf einmal, ohne "Listen" auf dem Client zu verarbeiten oder anderweitig "mehrere" Schreiboperationen zu akzeptieren, und vorzugsweise in "Batch"-Verarbeitung.

Daten sehen dann eher so aus (im Vergleich zu obigem Beispiel):

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        { "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
        { "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
    ]
}

Daher ist das eigentliche Abrufen der Daten nur eine Frage von:

db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });

Die Vor- und Nachteile von beiden hängen immer weitgehend vom Nutzungsmuster Ihrer Anwendung ab. Aber auf einen Blick:

Einbettung

  • Die Gesamtgröße des Dokuments mit eingebetteten Daten überschreitet in der Regel nicht 16 MB Speicherplatz (die BSON-Grenze) oder enthält ansonsten (als Richtlinie) Arrays mit 500 oder mehr Einträgen.

  • Eingebettete Daten erfordern im Allgemeinen keine häufigen Änderungen. Sie könnten also mit "Duplikaten" leben, die aus der Denormalisierung resultieren, was nicht dazu führt, dass diese "Duplikate" mit denselben Informationen in vielen übergeordneten Dokumenten aktualisiert werden müssen, nur um eine Änderung hervorzurufen.

  • Verwandte Daten werden häufig in Verbindung mit dem Elternteil verwendet. Das bedeutet, dass es sinnvoll ist, die Daten für atomare Operationen einzubetten, wenn Ihre "Lesen/Schreiben"-Fälle so ziemlich immer sowohl Eltern als auch Kind "lesen/schreiben" müssen.

Referenzierung

  • Die zugehörigen Daten werden immer die 16-MB-BSON-Grenze überschreiten. Sie können immer einen hybriden Ansatz des "Bucketing" in Betracht ziehen, aber die allgemeine harte Grenze des Hauptdokuments kann nicht überschritten werden. Häufige Fälle sind "Post" und "Kommentare", bei denen eine sehr große "Kommentar"-Aktivität zu erwarten ist.

  • Zugehörige Daten müssen regelmäßig aktualisiert werden. Oder im Wesentlichen der Fall, in dem Sie "normalisieren", weil diese Daten von vielen Eltern "geteilt" werden und die "zugehörigen" Daten häufig genug geändert werden, dass es unpraktisch wäre, eingebettete Elemente in jedem "Elternteil" zu aktualisieren, in dem dieses "Kind"-Element vorkommt . Der einfachere Fall ist, einfach auf das "Kind" zu verweisen und die Änderung einmal vorzunehmen.

  • Es gibt eine klare Trennung von Lesen und Schreiben. In dem Fall, in dem Sie diese "verwandten" Informationen möglicherweise nicht immer benötigen, wenn Sie das "Elternteil" lesen, oder das "Elternteil" nicht immer ändern müssen, wenn Sie an das Kind schreiben, könnte es einen guten Grund geben, das Modell zu trennen wie verwiesen. Wenn außerdem ein allgemeiner Wunsch besteht, viele "Unterdokumente" auf einmal zu aktualisieren, wobei diese "Unterdokumente" tatsächlich Verweise auf eine andere Sammlung sind, dann ist die Implementierung häufig effizienter, wenn sich die Daten in einer separaten befinden Sammlung.

Es gibt also tatsächlich eine viel breitere Diskussion der "Vor- und Nachteile" für beide Positionen in der MongoDB-Dokumentation zur Datenmodellierung, die verschiedene Anwendungsfälle und Vorgehensweisen abdeckt, entweder mit Einbettung oder mit referenziertem Modell, wie es von der Populate-Methode unterstützt wird.

Hoffentlich sind die "Punkte" von Nutzen, aber die allgemeine Empfehlung lautet, die Datennutzungsmuster Ihrer Anwendung zu berücksichtigen und das Beste auszuwählen. Die "Option" zum Einbetten "sollte" der Grund sein, warum Sie sich für MongoDB entschieden haben, aber es wird tatsächlich die Art und Weise sein, wie Ihre Anwendung "die Daten verwendet", die die Entscheidung trifft, welche Methode zu welchem ​​​​Teil Ihrer Datenmodellierung passt (da dies nicht der Fall ist "alles oder nichts") am besten.

  1. Beachten Sie, dass MongoDB, seit dies ursprünglich geschrieben wurde, den $lookup eingeführt hat -Operator, der tatsächlich "Joins" zwischen Sammlungen auf dem Server durchführt. Für die Zwecke der allgemeinen Diskussion hier ist es in den meisten Fällen "besser", dass der Mehraufwand durch "mehrere Abfragen" durch populate() verursacht wird und "mehrere Abfragen" im Allgemeinen gibt es immer noch einen "erheblichen Overhead" die durch $lookup entstehen Betrieb.

Das zentrale Designprinzip ist „eingebettet“ bedeutet „bereits vorhanden“ im Gegensatz zu „von woanders holen“. Im Wesentlichen der Unterschied zwischen "in der Tasche" und "im Regal", und in I/O-Begriffen normalerweise eher wie "im Regal in der Bibliothek in der Innenstadt" , und insbesondere weiter weg für netzwerkbasierte Anfragen.