133 votes

Qu'est-ce que l'opérateur $unwind dans MongoDB ?

C'est mon premier jour avec MongoDB, alors allez-y doucement avec moi :)

Je ne peux pas comprendre le $unwind opérateur, peut-être parce que l'anglais n'est pas ma langue maternelle.

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

L'opérateur de projet est quelque chose que je peux comprendre, je suppose (c'est comme SELECT n'est-ce pas ?). Mais alors, $unwind (citation) renvoie un document pour chaque membre du tableau déroulé dans chaque document source. .

Est-ce que c'est comme un JOIN ? Si oui, comment le résultat de $project (con _id , author , title y tags ) peuvent être comparés avec les tags le réseau ?

NOTE : J'ai pris l'exemple sur le site de MongoDB, je ne connais pas la structure de la base de données. tags le tableau. Je pense que c'est un simple tableau de noms de balises.

320voto

HGS Labs Points 3186

Tout d'abord, bienvenue à MongoDB !

Il ne faut pas oublier que MongoDB utilise une approche "NoSQL" du stockage des données, alors oubliez les sélections, les jointures, etc. MongoDB stocke vos données sous forme de documents et de collections, ce qui permet d'ajouter et d'obtenir les données de vos emplacements de stockage de manière dynamique.

Ceci étant dit, pour comprendre le concept derrière le paramètre $unwind, vous devez d'abord comprendre ce que dit le cas d'utilisation que vous essayez de citer. Le document d'exemple de mongodb.org est le suivant :

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

Remarquez que tags est en fait un tableau de 3 éléments, dans ce cas "fun", "good" et "fun".

Ce que $unwind fait, c'est vous permettre de découper un document pour chaque élément et retourner le document résultant. Dans une approche classique, ce serait l'équivalent de "pour chaque élément du tableau de balises, renvoyer un document contenant uniquement cet élément".

Ainsi, le résultat de l'exécution de ce qui suit :

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

retournerait les documents suivants :

{
     "result" : [
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "good"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             }
     ],
     "OK" : 1
}

Remarquez que la seule chose qui change dans le tableau de résultats est ce qui est renvoyé dans la valeur des balises. Si vous avez besoin d'une référence supplémentaire sur la façon dont cela fonctionne, j'ai inclus un lien aquí . J'espère que cela vous aidera, et bonne chance pour votre incursion dans l'un des meilleurs systèmes NoSQL que j'ai rencontrés jusqu'à présent.

55voto

JohnnyHK Points 61191

$unwind duplique chaque document dans le pipeline, une fois par élément du tableau.

Donc, si votre pipeline d'entrée contient un doc d'article avec deux éléments dans tags , {$unwind: '$tags'} transformerait le pipeline en deux documents d'articles identiques à l'exception de l'élément tags champ. Dans le premier document, tags contiendrait le premier élément du tableau du doc original, et dans le second doc, tags contiendrait le deuxième élément.

12voto

Pravin Points 71

Considérez l'exemple ci-dessous pour le comprendre Données dans une collection

{
        "_id" : 1,
        "shirt" : "Half Sleeve",
        "sizes" : [
                "medium",
                "XL",
                "free"
        ]
}

Requête -- db.test1.aggregate( [ { $unwind : "$sizes" } ] ) ;

sortie

{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }

5voto

FullStack Points 648

Selon la documentation officielle de mongodb :

$unwind Déconstruit un champ de tableau à partir des documents d'entrée afin de produire un document pour chaque élément. Chaque document de sortie est le document d'entrée avec la valeur du champ du tableau remplacée par l'élément.

Explication à l'aide d'un exemple de base :

Un inventaire de collection comporte les documents suivants :

{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }

Les $ suivants Détendez-vous sont équivalentes et renvoient un document pour chaque élément de la base de données. tailles champ. Si le champ de taille ne se résout pas en un tableau mais n'est pas manquant, nul ou vide, $unwind traite l'opérande non-réseau comme un tableau à un seul élément.

db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

ou

db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ] 

Le résultat de la requête ci-dessus :

{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }

Pourquoi est-il nécessaire ?

$unwind est très utile lors de l'exécution de l'agrégation. Il décompose les documents complexes/enchevêtrés en documents simples avant d'exécuter diverses opérations telles que le tri, la recherche, etc.

Pour en savoir plus sur $unwind :

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

Pour en savoir plus sur l'agrégation :

https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

3voto

Jeb50 Points 587

Laissez-moi vous expliquer d'une manière proche de celle des SGBDR. Voici l'énoncé :

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

à appliquer à la document / enregistrement :

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

El $project / Select renvoie simplement ces champs/colonnes comme

SÉLECTIONNER auteur, titre, balises DE article

Ensuite, c'est la partie amusante de Mongo, considérez ce tableau tags : [ "fun" , "good" , "fun" ] comme une autre table liée (qui ne peut pas être une table de consultation/référence car les valeurs comportent des doublons) nommée "tags". Rappelez-vous que SELECT produit généralement des choses verticales, donc dérouler les "tags" est de split() verticalement dans le tableau "tags".

Le résultat final de $project + $unwind : enter image description here

Traduire la sortie en JSON :

{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}

Parce que nous n'avons pas dit à Mongo d'omettre le champ "_id", il est donc ajouté automatiquement.

La clé est de faire en sorte que l'agrégation se fasse sous forme de tableau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X