Wie kann ich (in MongoDB) Daten aus mehreren Sammlungen in einer Sammlung kombinieren?
Kann ich Map-Reduce verwenden und wenn ja, wie?
Ich würde mich sehr über ein Beispiel freuen, da ich ein Neuling bin.
mongodb
mongodb-query
aggregation-framework
user697697
quelle
quelle
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});
reicht a aus. Bitte geben Sie Ihren verwendeten Treiber (Java, PHP, ...) an, wenn Sie keine Mongo-Shell verwenden.Antworten:
Obwohl Sie dies nicht in Echtzeit tun können, können Sie Map-Reduce mehrmals ausführen, um Daten zusammenzuführen, indem Sie die Option "Reduzieren" in MongoDB 1.8+ Map / Reduce verwenden (siehe http://www.mongodb.org/). display / DOCS / MapReduce # MapReduce-Outputoptions ). Sie benötigen einen Schlüssel in beiden Sammlungen, den Sie als _id verwenden können.
Angenommen, Sie haben eine
users
Sammlung und einecomments
Sammlung und möchten eine neue Sammlung mit einigen demografischen Benutzerinformationen für jeden Kommentar.Angenommen, die
users
Sammlung enthält die folgenden Felder:Und dann hat die
comments
Sammlung die folgenden Felder:Sie würden diese Karte machen / reduzieren:
Zu diesem Zeitpunkt haben Sie eine neue Sammlung mit dem Namen
users_comments
, die die zusammengeführten Daten enthält, und Sie können diese jetzt verwenden. Diese reduzierten Sammlungen haben alle_id
den Schlüssel, den Sie in Ihren Kartenfunktionen ausgegeben haben, und dann sind alle Werte ein Unterobjekt innerhalb desvalue
Schlüssels - die Werte befinden sich nicht auf der obersten Ebene dieser reduzierten Dokumente.Dies ist ein etwas einfaches Beispiel. Sie können dies mit mehr Sammlungen wiederholen, so oft Sie die reduzierte Sammlung weiter aufbauen möchten. Sie können dabei auch Zusammenfassungen und Aggregationen von Daten erstellen. Wahrscheinlich würden Sie mehr als eine Reduzierungsfunktion definieren, da die Logik zum Aggregieren und Beibehalten vorhandener Felder komplexer wird.
Sie werden auch feststellen, dass es jetzt für jeden Benutzer ein Dokument mit allen Kommentaren dieses Benutzers in einem Array gibt. Wenn wir Daten zusammenführen würden, die eher eine Eins-zu-Eins-Beziehung als eine Eins-zu-Viele-Beziehung haben, wäre dies flach und Sie könnten einfach eine Reduzierungsfunktion wie die folgende verwenden:
Wenn Sie die
users_comments
Sammlung reduzieren möchten, sodass es sich um ein Dokument pro Kommentar handelt, führen Sie zusätzlich Folgendes aus:Diese Technik sollte definitiv nicht im laufenden Betrieb durchgeführt werden. Es eignet sich für einen Cron-Job oder ähnliches, bei dem die zusammengeführten Daten regelmäßig aktualisiert werden. Möglicherweise möchten Sie
ensureIndex
die neue Sammlung ausführen, um sicherzustellen, dass Abfragen, die Sie für sie ausführen, schnell ausgeführt werden (denken Sie daran, dass sich Ihre Daten noch in einemvalue
Schlüssel befinden. Wenn Sie alsocomments_with_demographics
die Kommentarzeit indizierencreated
, ist dies der Falldb.comments_with_demographics.ensureIndex({"value.created": 1});
quelle
users_comments
Sammlung nach dem ersten Codeblock gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835Mit MongoDB 3.2 können jetzt Daten aus mehreren Sammlungen über die Aggregationsphase $ lookup zu einer zusammengefasst werden . Nehmen wir als praktisches Beispiel an, Sie haben Daten zu Büchern, die in zwei verschiedene Sammlungen aufgeteilt sind.
Erste Sammlung, genannt
books
, mit folgenden Daten:Und die zweite Sammlung
books_selling_data
mit den folgenden Daten:Um beide Sammlungen zusammenzuführen, müssen Sie $ lookup nur folgendermaßen verwenden:
Nach dieser Aggregation
books
sieht die Sammlung folgendermaßen aus:Es ist wichtig, einige Dinge zu beachten:
books_selling_data
nicht gesplittert werden.Wenn Sie also beide Sammlungen konsolidieren möchten und in diesem Fall ein flaches Feld copy_sold mit den insgesamt verkauften Kopien haben, müssen Sie ein wenig mehr arbeiten, wahrscheinlich mit einer Zwischensammlung, die dann sein $ aus der endgültigen Sammlung.
quelle
$lookup
sollten nicht alle "localField" und "ForeignField" gleich "isbn" sein? nicht "_id" und "isbn"?Wenn es keine Masseneinfügung in mongodb gibt, schleifen wir alle Objekte in die
small_collection
und fügen sie einzeln in die einbig_collection
:quelle
Sehr einfaches Beispiel mit $ lookup.
Hier wird verwendet
Anstatt
Aufgrund von {$ unwind: "$ userRoleData"} wird ein leeres oder 0-Ergebnis zurückgegeben, wenn mit $ lookup kein übereinstimmender Datensatz gefunden wurde.
quelle
Das Ausführen von Gewerkschaften in MongoDB in einer 'SQL UNION'-Weise ist möglich, indem Aggregationen zusammen mit Suchvorgängen in einer einzigen Abfrage verwendet werden. Hier ist ein Beispiel, das ich getestet habe und das mit MongoDB 4.0 funktioniert:
Hier ist die Erklärung, wie es funktioniert:
Instanziieren Sie ein
aggregate
Out aus einer Sammlung Ihrer Datenbank, die mindestens ein Dokument enthält. Wenn Sie nicht garantieren können, dass eine Sammlung Ihrer Datenbank nicht leer ist, können Sie dieses Problem umgehen, indem Sie in Ihrer Datenbank eine Art "Dummy" -Sammlung erstellen, die ein einzelnes leeres Dokument enthält, das speziell für die Durchführung von Gewerkschaftsabfragen vorgesehen ist.Machen Sie die erste Stufe Ihrer Pipeline
{ $limit: 1 }
. Dadurch werden alle Dokumente der Sammlung mit Ausnahme des ersten entfernt.Entfernen Sie alle Felder des verbleibenden Dokuments mithilfe einer
$project
Stufe:Ihr Aggregat enthält jetzt ein einzelnes, leeres Dokument. Es ist Zeit, Lookups für jede Sammlung hinzuzufügen, die Sie zusammenführen möchten. Sie können die verwenden
pipeline
Feld verwenden, um eine bestimmte Filterung durchzuführen, oder lassenlocalField
undforeignField
als Null, um mit der gesamten Sammlung übereinzustimmen.Sie haben jetzt ein Aggregat, das ein einzelnes Dokument enthält, das drei Arrays wie folgt enthält:
Sie können sie dann mit a zu einem einzigen Array zusammenführen
$project
Stufe zusammen mit dem$concatArrays
Aggregationsoperator zusammenführen :Sie haben jetzt ein Aggregat mit einem einzelnen Dokument, in dem sich ein Array befindet, das Ihre Vereinigung von Sammlungen enthält. Was noch zu tun bleibt, ist das Hinzufügen eines
$unwind
und einer$replaceRoot
Stufe, um Ihr Array in separate Dokumente aufzuteilen:Voilà. Sie haben jetzt eine Ergebnismenge mit den Sammlungen, die Sie zusammenführen möchten. Sie können dann weitere Stufen hinzufügen, um es weiter zu filtern, zu sortieren, skip () und limit () anzuwenden. So ziemlich alles was du willst.
quelle
Verwenden Sie mehrere $ lookup für mehrere Sammlungen in Aggregation
Abfrage:
Ergebnis:
quelle
Mongorestore verfügt über diese Funktion zum Anhängen an das, was bereits in der Datenbank vorhanden ist. Daher kann dieses Verhalten zum Kombinieren von zwei Sammlungen verwendet werden:
Ich habe es noch nicht ausprobiert, aber es funktioniert möglicherweise schneller als der Map / Reduce-Ansatz.
quelle
Ab
Mongo 4.4
sofort können wir diesen Join innerhalb einer Aggregationspipeline erreichen, indem wir die neue$unionWith
Aggregationsstufe mit$group
dem neuen$accumulator
Operator koppeln:$unionWith
kombiniert Datensätze aus der angegebenen Sammlung in Dokumenten, die sich bereits in der Aggregationspipeline befinden. Nach den beiden Gewerkschaftsphasen haben wir somit alle Benutzer-, Buch- und Filmaufzeichnungen in der Pipeline.Wir
$group
zeichnen dann$user
Elemente auf und akkumulieren sie mithilfe des$accumulator
Operators, sodass benutzerdefinierte Akkumulationen von Dokumenten möglich sind, sobald sie gruppiert werden:accumulateArgs
.init
definiert den Zustand, der beim Gruppieren von Elementen akkumuliert wird.accumulate
Funktion können Sie eine benutzerdefinierte Aktion ausführen, wobei ein Datensatz gruppiert wird, um den akkumulierten Status zu erstellen. Wenn für das zu gruppierende Element beispielsweise dasbook
Feld definiert ist, aktualisieren wir denbooks
Teil des Status.merge
wird verwendet, um zwei interne Zustände zusammenzuführen. Es wird nur für Aggregationen verwendet, die auf Sharded-Clustern ausgeführt werden oder wenn der Vorgang die Speichergrenzen überschreitet.quelle
Ja, Sie können: Nehmen Sie diese Dienstprogrammfunktion, die ich heute geschrieben habe:
Sie können an diese Funktion eine beliebige Anzahl von Sammlungen übergeben, wobei die erste die Zielsammlung sein wird. Alle übrigen Sammlungen sind Quellen, die an die Zielsammlung übertragen werden sollen.
quelle
Code-Auszug. Courtesy-Mehrere Beiträge zum Stapelüberlauf, einschließlich dieses.
quelle
Sie müssen dies in Ihrer Anwendungsschicht tun. Wenn Sie ein ORM verwenden, können Anmerkungen (oder ähnliches) verwendet werden, um Referenzen abzurufen, die in anderen Sammlungen vorhanden sind. Ich habe nur mit Morphia gearbeitet , und die
@Reference
Anmerkung ruft die referenzierte Entität ab, wenn sie abgefragt wird, sodass ich es vermeiden kann, dies selbst im Code zu tun.quelle