Wie lautet die Syntax für eine $ -Suche in einem Feld, das ein Array von ObjectIds und nicht nur eine einzelne ObjectId ist?
Beispiel für ein Bestelldokument:
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
]
}
Nicht funktionierende Abfrage:
db.orders.aggregate([
{
$lookup:
{
from: "products",
localField: "products",
foreignField: "_id",
as: "productObjects"
}
}
])
Erwünschtes Ergebnis
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
],
productObjects: [
{<Car Object>},
{<Bike Object>}
],
}
mongodb
mongodb-query
aggregation-framework
Jason Lin
quelle
quelle
Antworten:
Update 2017
$ lookup kann jetzt direkt ein Array als lokales Feld verwenden .
$unwind
wird nicht mehr benötigt.Alte Antwort
Die
$lookup
Phase der Aggregationspipeline funktioniert nicht direkt mit einem Array. Die Hauptabsicht des Entwurfs besteht darin, einen "linken Join" als einen "Eins-zu-Viele" -Typ (oder wirklich einen "Lookup") für die möglichen verwandten Daten zu erstellen. Der Wert soll jedoch singulär und kein Array sein.Daher müssen Sie den Inhalt zuerst "de-normalisieren", bevor Sie den
$lookup
Vorgang ausführen, damit dies funktioniert. Und das bedeutet$unwind
:Nach
$lookup
Übereinstimmungen mit jedem Array-Mitglied ist das Ergebnis ein Array selbst, so dass Sie$unwind
erneut und$group
zu$push
neuen Arrays für das Endergebnis.Beachten Sie, dass alle nicht gefundenen "Left Join" -Matches ein leeres Array für die "productObjects" des angegebenen Produkts erstellen und somit das Dokument für das "product" -Element negieren, wenn das zweite
$unwind
aufgerufen wird.Obwohl eine direkte Anwendung auf ein Array nett wäre, funktioniert dies derzeit nur, indem ein einzelner Wert mit einer möglichen Anzahl von Werten abgeglichen wird.
Da
$lookup
es im Grunde genommen sehr neu ist, funktioniert es derzeit so, wie es denjenigen bekannt ist, die mit Mungo als "Version des armen Mannes" der.populate()
dort angebotenen Methode vertraut sind . Der Unterschied besteht darin, dass$lookup
die "serverseitige" Verarbeitung des "Joins" im Gegensatz zum Client angeboten wird und dass$lookup
derzeit ein Teil der "Reife" fehlt.populate()
Angeboten (z. B. das Interpolieren der Suche direkt auf einem Array).Dies ist tatsächlich ein zugewiesenes Problem zur Verbesserung von SERVER-22881 . Mit etwas Glück würde dies die nächste Version oder eine bald danach treffen.
Als Entwurfsprinzip ist Ihre aktuelle Struktur weder gut noch schlecht, sondern unterliegt nur dem Overhead beim Erstellen eines "Joins". Als solches gilt das Grundprinzip von MongoDB in der Anfangszeit. Wenn Sie mit den Daten "leben" können, die in einer Sammlung "vorverknüpft" sind, ist es am besten, dies zu tun.
Das andere, was
$lookup
als allgemeines Prinzip gesagt werden kann , ist, dass die Absicht des "Joins" hier darin besteht, umgekehrt zu arbeiten als hier gezeigt. Anstatt die "verwandten IDs" der anderen Dokumente im "übergeordneten" Dokument zu belassen, funktioniert das allgemeine Prinzip am besten, wenn die "verwandten Dokumente" einen Verweis auf das "übergeordnete Dokument" enthalten.Man
$lookup
kann also sagen, dass es mit einem "Beziehungsdesign" "am besten funktioniert", das das Gegenteil davon ist, wie etwas wie Mungo.populate()
seine clientseitigen Verknüpfungen ausführt. Indem Sie stattdessen das "Eins" in jedem "Viele" identifizieren, ziehen Sie einfach die zugehörigen Elemente ein, ohne$unwind
zuerst das Array zu benötigen .quelle
$lookup
und Dokumentvalidierung im Allgemeinen als Merkmale in den Kinderschuhen behandelt, die sich wahrscheinlich verbessern werden. Eine direkte Erweiterung eines Arrays wäre daher ebenso willkommen wie eine "Abfrage" zum Filtern der Ergebnisse. Beide wären viel mehr auf den Mungo-.populate()
Prozess ausgerichtet, an den viele gewöhnt sind. Hinzufügen des Problemlinks direkt zum Antwortinhalt.$lookup
jetzt direkt auf einem Array funktioniert.Ab MongoDB v3.4 (veröffentlicht im Jahr 2016) kann die
$lookup
Phase der Aggregationspipeline auch direkt mit einem Array arbeiten . Es besteht keine Notwendigkeit$unwind
mehr.Dies wurde in SERVER-22881 verfolgt .
quelle
Sie können die
pipeline
Stufe auch verwenden , um Überprüfungen für ein Subdokumentationsarray durchzuführenHier ist das Beispiel mit
python
(sorry, ich bin Schlangenmenschen).Der Haken hier ist, alle Objekte in der
ObjectId
array
(fremde_id
, die inlocal
Feld / Requisite istproducts
) abzugleichen .Sie können die ausländischen Datensätze auch bereinigen oder mit zusätzlichen
stage
s projizieren , wie im obigen Kommentar angegeben.quelle
Mit $ unwind erhalten Sie das erste Objekt anstelle eines Array von Objekten
Abfrage:
Ergebnis:
quelle
Das Aggregieren mit
$lookup
und im Anschluss$group
ist ziemlich umständlich. Wenn Sie also Node & Mongoose oder eine unterstützende Bibliothek mit einigen Hinweisen im Schema verwenden (und das ist ein Medium, wenn), können Sie.populate()
diese Dokumente mit a abrufen:quelle
Ich muss nicht zustimmen, wir können dafür sorgen, dass $ lookup mit dem IDs-Array funktioniert, wenn wir ihm die $ match-Phase voranstellen.
Es wird komplizierter, wenn wir das Suchergebnis an eine Pipeline übergeben möchten. Andererseits gibt es eine Möglichkeit, dies zu tun (bereits von @ user12164 vorgeschlagen):
quelle