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

$lookup auf ObjectIds in einem Array

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.