MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

$lookup sur ObjectId dans un tableau

Mise à jour 2017

$lookup peut désormais utiliser directement un tableau comme champ local. $unwind n'est plus nécessaire.

Ancienne réponse

La $lookup l'étape de pipeline d'agrégation ne fonctionnera pas directement avec un tableau. L'intention principale de la conception est une "jointure gauche" en tant que type de jointure "un à plusieurs" (ou vraiment une "recherche") sur les données associées possibles. Mais la valeur est censée être singulière et non un tableau.

Par conséquent, vous devez d'abord "dénormaliser" le contenu avant d'effectuer la $lookup opération pour que cela fonctionne. Et cela signifie utiliser $unwind :

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" }
    }}
])

Après $lookup correspond à chaque membre du tableau, le résultat est un tableau lui-même, donc vous $unwind à nouveau et $group à $push nouveaux tableaux pour le résultat final.

Notez que toute correspondance de "jointure gauche" introuvable créera un tableau vide pour les "productObjects" sur le produit donné et annulera ainsi le document pour l'élément "product" lorsque le second $unwind est appelé.

Bien qu'une application directe à un tableau serait bien, c'est comme ça que cela fonctionne actuellement en faisant correspondre une valeur singulière à un nombre possible.

Comme $lookup est fondamentalement très nouveau, il fonctionne actuellement comme le savent ceux qui connaissent la mangouste en tant que "version pauvre" du .populate() méthode qui y est proposée. La différence étant que $lookup offre un traitement "côté serveur" de la "jointure" par opposition au client et qu'une partie de la "maturité" dans $lookup manque actuellement de ce que .populate() offres (telles que l'interpolation de la recherche directement sur un tableau).

Il s'agit en fait d'un problème assigné à l'amélioration SERVER-22881, donc avec un peu de chance, cela arrivera dans la prochaine version ou une peu après.

En tant que principe de conception, votre structure actuelle n'est ni bonne ni mauvaise, mais juste sujette à des frais généraux lors de la création d'une "jointure". En tant que tel, le principe permanent de base de MongoDB au départ s'applique, où si vous "pouvez" vivre avec les données "pré-jointes" dans une seule collection, alors il est préférable de le faire.

La seule autre chose que l'on peut dire de $lookup en règle générale, l'intention de la "jointure" ici est de fonctionner dans l'autre sens que celui illustré ici. Ainsi, plutôt que de conserver les "identifiants associés" des autres documents dans le document "parent", le principe général qui fonctionne le mieux est que les "documents associés" contiennent une référence au "parent".

Donc $lookup on peut dire qu'il "fonctionne mieux" avec une "conception de relation" qui est l'inverse de la façon dont quelque chose comme la mangouste .populate() effectue ses jointures côté client. En identifiant le "un" dans chaque "plusieurs" à la place, vous tirez simplement les éléments associés sans avoir besoin de $unwind le tableau en premier.