Aktualisierung 2017
$lookup kann jetzt direkt ein Array als lokales Feld verwenden. $unwind
wird nicht mehr benötigt.
Alte Antwort
Die $lookup
Die Phase der Aggregationspipeline funktioniert nicht direkt mit einem Array. Die Hauptabsicht des Entwurfs ist eine „Linksverknüpfung“ als „Eins-zu-Viele“-Verknüpfungsart (oder wirklich ein „Nachschlagen“ ) der möglichen verwandten Daten. Aber der Wert soll singulär sein und kein Array.
Daher müssen Sie den Inhalt zuerst "denormalisieren", bevor Sie $lookup
ausführen Betrieb, damit dies funktioniert. Und das bedeutet, $unwind
zu verwenden :
db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
Nach $lookup
mit jedem Arraymitglied übereinstimmt, ist das Ergebnis selbst ein Array, also $unwind
erneut und $group
zu $push
neue Arrays für das Endergebnis.
Beachten Sie, dass alle nicht gefundenen "Left Join"-Übereinstimmungen ein leeres Array für die "productObjects" für das angegebene Produkt erstellen und somit das Dokument für das "product"-Element beim zweiten $unwind
negieren heißt.
Obwohl eine direkte Anwendung auf ein Array schön wäre, funktioniert dies derzeit einfach so, indem ein einzelner Wert mit einer möglichen Anzahl von Werten abgeglichen wird.
Als $lookup
ist im Grunde sehr neu, es funktioniert derzeit so, wie es denen vertraut wäre, die mit Mungo als "Arme-Mann-Version" der .populate()
vertraut sind dort angebotene Methode. Der Unterschied besteht darin, dass $lookup
bietet eine "serverseitige" Verarbeitung des "join" im Gegensatz zu der auf dem Client und dass einige der "Reife" in $lookup
derzeit fehlt was .populate()
bietet (wie z. B. das direkte Interpolieren der Suche auf einem Array).
Dies ist eigentlich ein zugewiesenes Problem für die Verbesserung SERVER-22881, also würde dies mit etwas Glück die nächste Version oder eine bald darauf treffen.
Als Entwurfsprinzip ist Ihre aktuelle Struktur weder gut noch schlecht, sondern unterliegt nur dem Overhead, wenn Sie einen "Join" erstellen. Als solches gilt das Grundprinzip von MongoDB in der Anfangsphase:Wenn Sie mit den Daten leben „können“, die in einer Sammlung „vorab verbunden“ sind, dann ist es am besten, dies zu tun.
Die eine andere Sache, die man über $lookup
sagen kann Als allgemeines Prinzip gilt, dass die Absicht des "Verknüpfens" hier darin besteht, andersherum als hier gezeigt zu funktionieren. Anstatt die "zugehörigen IDs" der anderen Dokumente innerhalb des "übergeordneten" Dokuments zu behalten, funktioniert das allgemeine Prinzip am besten dort, wo die "zugehörigen Dokumente" einen Verweis auf das "übergeordnete" Dokument enthalten.
Also $lookup
kann gesagt werden, dass es mit einem "Beziehungsdesign" "am besten funktioniert", das das Gegenteil von etwas wie Mongoose .populate()
ist führt seine clientseitigen Verknüpfungen durch. Indem Sie stattdessen das "Eins" in jedem "Vielen" identifizieren, ziehen Sie einfach die zugehörigen Elemente ein, ohne $unwind
zu müssen das Array zuerst.