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 du projet est quelque chose que je peux comprendre, je suppose (c’est comme SELECT
, n’est-ce pas?). Mais alors, $unwind
(citing) renvoie un document pour chaque membre du tableau non déroulé de chaque document source .
Est-ce comme un JOIN
? Si oui, comment le résultat de $project
(avec _id
, author
, title
et tags
champs) peuvent être comparés au tableau tags
?
NOTE : J'ai pris l'exemple du site Web MongoDB, je ne connais pas la structure du tableau tags
. Je pense que c'est un simple tableau de noms de balises.
Tout d’abord, bienvenue sur MongoDB!
La chose à retenir est que MongoDB utilise une approche "NoSQL" pour le stockage de données, alors perdez l'esprit de vos pensées, des jointures, etc. La manière dont il stocke vos données se présente sous la forme de documents et de collections, ce qui permet un moyen dynamique d’ajouter et d’obtenir les données à partir de vos emplacements de stockage.
Cela dit, pour comprendre le concept du paramètre $ undind, 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 }
}
Notez que les balises sont en réalité un tableau de 3 éléments, dans ce cas-ci "amusement", "bien" et "amusement".
Ce que fait $ unwinde vous permet de détacher un document pour chaque élément et de retourner le document résultant. Pour penser à cela dans une approche classique, cela équivaudrait à "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" }
);
renverrait 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
}
Notez que la seule chose qui change dans le tableau de résultats est ce qui est retourné 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 ici . J'espère que cela vous aidera, et bonne chance dans votre incursion dans l'un des meilleurs systèmes NoSQL que j'ai rencontrés jusqu'à présent.
$unwind
duplique chaque document du pipeline, une fois par élément de tableau.
Donc, si votre pipeline d’entrée contient un document d’article contenant deux éléments dans tags
, {$unwind: '$tags'}
transformerait le pipeline en deux documents d’article identiques, à l’exception du champ tags
. Dans le premier document, tags
contiendrait le premier élément du tableau du document d'origine et dans le second document, tags
contiendrait le deuxième élément.
Comprenons cela par un exemple
Voici à quoi ressemble le document company :
Le $unwind
nous permet de prendre en entrée des documents comportant un champ de valeur de tableau et de générer des documents de sortie, de sorte qu’il existe un document de sortie pour chaque élément du tableau. source
Revenons donc à nos exemples d'entreprises et examinons l'utilisation des étapes de déroulement. Cette requête:
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
produit des documents contenant des tableaux pour le montant et l'année.
Parce que nous avons accès au montant recueilli et à l’année de financement pour chaque élément du tableau des rondes de financement. Pour résoudre ce problème, nous pouvons inclure une étape de décompression avant la phase de projet dans ce pipeline d'agrégation et paramétrer ceci en indiquant que nous voulons unwind
le tableau des tours de financement:
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $unwind: "$funding_rounds" },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
Si on regarde le funding_rounds
tableau, nous savons que pour chaque funding_rounds
, Il y a un raised_amount
et un funded_year
champ. Donc, unwind
sera pour chacun des documents qui sont des éléments du funding_rounds
tableau produit un document de sortie. Maintenant, dans cet exemple, nos valeurs sont string
s. Mais, quel que soit le type de valeur pour les éléments d'un tableau, unwind
produira un document de sortie pour chacune de ces valeurs, de sorte que le champ en question contiendra uniquement cet élément. Dans le cas de funding_rounds
, cet élément sera l’un de ces documents comme valeur pour funding_rounds
pour chaque document transmis à notre stade project
. Le résultat, après avoir exécuté ceci, est que nous obtenons maintenant un amount
et un year
. Un pour chaque tour de financement pour chaque entreprise de notre collection. Cela signifie que notre correspondance a généré de nombreux documents d'entreprise et que chacun de ces documents résulte en de nombreux documents. Un pour chaque tour de financement dans chaque document d'entreprise. unwind
effectue cette opération en utilisant les documents qui lui sont transmis à partir de l'étape match
. Et tous ces documents pour chaque entreprise sont ensuite passés à l'étape project
.
Ainsi, tous les documents dont le bailleur de fonds était Greylock (comme dans l'exemple de requête) seront scindés en un nombre de documents égal au nombre de tours de financement. pour chaque entreprise correspondant au filtre $match: {"funding_rounds.investments.financial_org.permalink": "greylock" }
. Et chacun de ces documents sera ensuite transmis à notre project
. Maintenant, unwind
produit une copie exacte de chacun des documents reçus en entrée. Tous les champs ont la même clé et la même valeur, à une exception près: le funding_rounds
champ plutôt que d'être un tableau de funding_rounds
documents a plutôt une valeur qui est un document unique, qui est un tour de financement individuel. Ainsi, une entreprise qui a 4 tours de financement aboutira à unwind
création 4 documents. Où chaque champ est une copie exacte, à l'exception du funding_rounds
champ, qui au lieu d’être un tableau pour chacune de ces copies sera plutôt un élément individuel du funding_rounds
tableau du document de l'entreprise que unwind
est en train de traiter. Ainsi, unwind
a pour effet d’afficher à l’étape suivante plus de documents qu’elle ne reçoit en entrée. Ce que cela signifie, c'est que notre scène project
obtient maintenant un funding_rounds
champ qui, encore une fois, n’est pas un tableau, mais un document imbriqué qui a un raised_amount
et un funded_year
champ. Ainsi, project
recevra plusieurs documents pour chaque entreprise match
ing le filtre et pourra donc traiter chaque document individuellement et identifier un montant individuel et une année pour chaque tour de financement pour chaque entreprise .
Selon la documentation officielle de mongodb:
$ déroulé Déconstruit un champ de tableau à partir des documents d'entrée pour générer un document pour chaque élément. Chaque document de sortie est le document d'entrée avec la valeur du champ de tableau remplacé par l'élément.
Explication par exemple de base:
Un inventaire de collection comprend 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 opérations $ dérouler suivantes sont équivalentes et renvoient un document pour chaque élément du champ tailles. Si le champ de tailles ne se résout pas en un tableau mais qu'il ne manque ni à null ni à un tableau vide, $ unwind traite l'opérande non-tableau comme un tableau à élément unique.
db.inventory.aggregate( [ { $unwind: "$sizes" } ] )
ou
db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ]
Sortie de 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-ce nécessaire?
$ unwind est très utile pour effectuer une agrégation. il divise un document complexe/imbriqué en un simple document avant d'effectuer diverses opérations telles que le tri, la recherche, etc.
Pour en savoir plus sur $ dérouler:
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/
Permettez-moi de vous expliquer de manière corrélée au SGBDR. C'est la déclaration:
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
appliquer au document/record:
{
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 }
}
Le $ projet/Select renvoie simplement ces champs/colonnes comme
[~ # ~] sélectionnez [~ # ~] auteur, titre, tags [~ # ~] de [~ # ~] article
Suivant la partie amusante de Mongo, considérons ce tableau tags : [ "fun" , "good" , "fun" ]
comme une autre table liée (ne peut pas être une table de consultation/référence car les valeurs ont une duplication) nommée "balises". Rappelez-vous que SELECT produit généralement des objets à la verticale, aussi dérouler les "tags" à scinder () verticalement dans le tableau "tags".
Le résultat final de $ projet + $ dérouler:
Traduisez 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 le rendre semblable à une table pour effectuer une agrégation.
considérez l'exemple ci-dessous pour comprendre ces données dans une collection.
{
"_id" : 1,
"shirt" : "Half Sleeve",
"sizes" : [
"medium",
"XL",
"free"
]
}
Requête - db.test1.aggregate ([{$ dérouler: "$ tailles"}]);
sortie
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }