Verwenden von JOINs in MongoDB NoSQL-Datenbanken

Verwenden von $ lookUp mit NoSQL

Vielen Dank an Julian Motz für die freundliche Unterstützung beim Peer-Review dieses Artikels.

Einer der größten Unterschiede zwischen SQL- und NoSQL-Datenbanken ist JOIN. In relationalen Datenbanken können Sie mit der SQL JOIN-Klausel Zeilen aus zwei oder mehr Tabellen mithilfe eines gemeinsamen Felds kombinieren. Wenn Sie beispielsweise Tabellen mit books und publishers haben, können Sie SQL-Befehle schreiben wie:

SELECT book.title, publisher.nameFROM bookLEFT JOIN book.publisher_id ON publisher.id;

Mit anderen Worten, die Tabelle book verfügt über ein Feld publisher_id, das auf das Feld id in der Tabelle publisher verweist.

Dies ist praktisch, da ein einziger Verlag Tausende von Büchern anbieten kann. Wenn wir jemals die Details eines Herausgebers aktualisieren müssen, können wir einen einzelnen Datensatz ändern. Die Datenredundanz wird minimiert, da wir die Verlegerinformationen nicht für jedes Buch wiederholen müssen. Diese Technik wird als Normalisierung bezeichnet.

SQL-Datenbanken bieten eine Reihe von Normalisierungs- und Einschränkungsfunktionen, um sicherzustellen, dass Beziehungen aufrechterhalten werden.

NoSQL == Kein JOIN?

Nicht immer …

Dokumentenorientierte Datenbanken wie MongoDB dienen zum Speichern denormalisierter Daten. Idealerweise sollte es keine Beziehung zwischen Sammlungen geben. Wenn in zwei oder mehr Dokumenten dieselben Daten erforderlich sind, müssen diese wiederholt werden.

Dies kann frustrierend sein, da es nur wenige Situationen gibt, in denen Sie niemals relationale Daten benötigen. Glücklicherweise führt MongoDB 3.2 einen neuen Operator $lookup ein, der eine LEFT-OUTER-JOIN-ähnliche Operation für zwei oder mehr Sammlungen ausführen kann. Aber es gibt einen Haken …

MongoDB-Aggregation

$lookup ist nur in Aggregationsoperationen zulässig. Stellen Sie sich diese als eine Pipeline von Operatoren vor, die ein Ergebnis abfragen, filtern und gruppieren. Die Ausgabe eines Operators wird als Eingabe für den nächsten verwendet.

Aggregation ist schwieriger zu verstehen als einfachere find Abfragen und wird im Allgemeinen langsamer ausgeführt. Sie sind jedoch leistungsstark und eine unschätzbare Option für komplexe Suchvorgänge.

Aggregation lässt sich am besten anhand eines Beispiels erklären. Angenommen, wir erstellen eine Social-Media-Plattform mit einer user -Sammlung. Es speichert die Details jedes Benutzers in separaten Dokumenten. Zum Beispiel:

{ "_id": ObjectID("45b83bda421238c76f5c1969"), "name": "User One", "email: "[email protected]", "country": "UK", "dob": ISODate("1999-09-13T00:00:00.000Z")}

Wir können so viele Felder wie nötig hinzufügen, aber alle MongoDB-Dokumente erfordern ein _id -Feld mit einem eindeutigen Wert. Der _id ähnelt einem SQL-Primärschlüssel und wird bei Bedarf automatisch eingefügt.

Unser soziales Netzwerk benötigt jetzt eine post -Sammlung, in der zahlreiche aufschlussreiche Updates von Benutzern gespeichert sind. Die Dokumente speichern den Text, das Datum, eine Bewertung und einen Verweis auf den Benutzer, der ihn geschrieben hat, in einem Feld user_id:

{ "_id": ObjectID("17c9812acff9ac0bba018cc1"), "user_id": ObjectID("45b83bda421238c76f5c1969"), "date: ISODate("2016-09-05T03:05:00.123Z"), "text": "My life story so far", "rating": "important"}

Wir möchten nun die letzten zwanzig Beiträge mit einer „wichtigen“ Bewertung aller Benutzer in umgekehrter chronologischer Reihenfolge anzeigen. Jedes zurückgegebene Dokument sollte den Text, die Uhrzeit des Beitrags sowie den Namen und das Land des zugehörigen Benutzers enthalten.

Der MongoDB-Aggregatabfrage wird ein Array von Pipeline-Operatoren übergeben, die jede Operation der Reihe nach definieren. Zuerst müssen wir alle Dokumente aus der post -Sammlung extrahieren, die die richtige Bewertung mit dem $match -Filter haben:

{ "$match": { "rating": "important" } }

Wir müssen nun die übereinstimmenden Elemente mit dem Operator $sort in umgekehrter Datumsreihenfolge sortieren:

{ "$sort": { "date": -1 } }

Da wir nur zwanzig Beiträge benötigen, können wir eine $limit -Stufe anwenden, sodass MongoDB nur die gewünschten Daten verarbeiten muss:

{ "$limit": 20 }

Wir können jetzt Daten aus der Sammlung user mit dem neuen Operator $lookup verknüpfen. Es erfordert ein Objekt mit vier Parametern:

  • localField: das Nachschlagefeld im Eingabedokument
  • from: die Sammlung zum Mitmachen
  • foreignField: das zu suchende Feld in der Sammlung from
  • as: der Name des Ausgabefelds.

Unser Operator ist daher:

{ "$lookup": { "localField": "user_id", "from": "user", "foreignField": "_id", "as": "userinfo"} }

Dadurch wird in unserer Ausgabe ein neues Feld mit dem Namen userinfo erstellt. Es enthält ein Array, in dem jeder Wert dem user -Dokument entspricht:

"userinfo": 

Wir haben eine Eins-zu-Eins-Beziehung zwischen post.user_id und user._id, da ein Beitrag nur einen Autor haben kann. Daher enthält unser Array userinfo immer nur ein Element. Wir können den Operator $unwind verwenden, um ihn in ein Unterdokument zu dekonstruieren:

{ "$unwind": "$userinfo" }

Die Ausgabe wird nun in ein praktischeres Format konvertiert, auf das weitere Operatoren angewendet werden können:

"userinfo": { "name": "User One", "email: "[email protected]", …}

Schließlich können wir den Text, die Uhrzeit des Beitrags, den Namen und das Land des Benutzers mithilfe einer $project -Stufe in der Pipeline zurückgeben:

{ "$project": { "text": 1, "date": 1, "userinfo.name": 1, "userinfo.country": 1} }

Alles zusammenfügen

Unsere endgültige Aggregatabfrage stimmt mit Posts überein, sortiert nach Reihenfolge, beschränkt sich auf die letzten zwanzig Elemente, verknüpft Benutzerdaten, reduziert das Benutzerarray und gibt nur die erforderlichen Felder zurück. Der vollständige Befehl:

db.post.aggregate();

Das Ergebnis ist eine Sammlung von bis zu zwanzig Dokumenten. Beispielsweise:

Großartig! Ich kann endlich zu NoSQL wechseln!

MongoDB $lookup ist nützlich und leistungsstark, aber selbst dieses grundlegende Beispiel erfordert eine komplexe Aggregatabfrage. Es ist kein Ersatz für die leistungsfähigere JOIN-Klausel, die in SQL angeboten wird. MongoDB bietet auch keine Einschränkungen; Wenn ein user -Dokument gelöscht wird, bleiben verwaiste post -Dokumente erhalten.

Idealerweise sollte der Operator $lookup selten benötigt werden. Wenn Sie es häufig benötigen, verwenden Sie möglicherweise den falschen Datenspeicher …

Wenn Sie relationale Daten haben, verwenden Sie eine relationale (SQL) Datenbank!

Das heißt, $lookup ist eine willkommene Ergänzung zu MongoDB 3.2. Es kann einige der frustrierenderen Probleme überwinden, wenn kleine Mengen relationaler Daten in einer NoSQL-Datenbank verwendet werden.

You might also like

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.