J'ai une exigence où je dois faire une agrégation sur deux enregistrements ont tous deux un champ de tableau avec une valeur différente. Ce dont j'ai besoin, lorsque je fais une agrégation sur ces enregistrements, le résultat doit avoir un tableau avec des valeurs uniques des deux tableaux différents. Voici un exemple:
Premier enregistrement
{ Host:"abc.com" ArtId:"123", tags:[ "tag1", "tag2" ] }
Deuxième enregistrement
{ Host:"abc.com" ArtId:"123", tags:[ "tag2", "tag3" ] }
Après l'agrégation sur l'hôte et l'artid, j'ai besoin d'un résultat comme celui-ci:
{ Host: "abc.com", ArtId: "123", count :"2", tags:[ "tag1", "tag2", "tag3" ]}
J'ai essayé $addToset
dans la déclaration de groupe mais cela me donne des balises comme celles-ci:[["tag1","tag2"],["tag2","tag3"]]
Pourriez-vous s'il vous plaît m'aider comment je peux y parvenir en agrégation
Les versions modernes devraient utiliser $reduce
avec $setUnion
après la première $group
comme le montre:
db.collection.aggregate([
{ "$group": {
"_id": { "Host": "$Host", "ArtId": "$ArtId" },
"count": { "$sum": 1 },
"tags": { "$addToSet": "$tags" }
}},
{ "$addFields": {
"tags": {
"$reduce": {
"input": "$tags",
"initialValue": [],
"in": { "$setUnion": [ "$$value", "$$this" ] }
}
}
}}
])
Vous aviez raison de trouver l' $addToSet
opérateur, mais lorsque vous travaillez avec du contenu dans un tableau, vous devez généralement traiter d' $unwind
abord avec . Cela «dé-normalise» les entrées du tableau et fait essentiellement une «copie» du document parent avec chaque entrée du tableau comme valeur singulière dans le champ. C'est ce dont vous avez besoin pour éviter le comportement que vous voyez sans l'utiliser.
Votre "compte" pose cependant un problème intéressant, mais facilement résolu grâce à l'utilisation d'un "double déroulement" après une $group
opération initiale :
db.collection.aggregate([
// Group on the compound key and get the occurrences first
{ "$group": {
"_id": { "Host": "$Host", "ArtId": "$ArtId" },
"tcount": { "$sum": 1 },
"ttags": { "$push": "$tags" }
}},
// Unwind twice because "ttags" is now an array of arrays
{ "$unwind": "$ttags" },
{ "$unwind": "$ttags" },
// Now use $addToSet to get the distinct values
{ "$group": {
"_id": "$_id",
"tcount": { "$first": "$tcount" },
"tags": { "$addToSet": "$ttags" }
}},
// Optionally $project to get the fields out of the _id key
{ "$project": {
"_id": 0,
"Host": "$_id.Host",
"ArtId": "$_id.ArtId",
"count": "$tcount",
"tags": "$ttags"
}}
])
Ce dernier bit avec $project
est également là parce que j'ai utilisé des noms «temporaires» pour chacun des champs dans les autres étapes du pipeline d'agrégation. En effet, il existe une optimisation en ce sens $project
que "copie" les champs d'une étape existante dans l'ordre dans lequel ils sont déjà apparus "avant que" tout "nouveau" champ ne soit ajouté au document.
Sinon, la sortie ressemblerait à:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
Où les champs ne sont pas dans le même ordre que vous pourriez le penser. Trivial vraiment, mais cela compte pour certaines personnes, il vaut donc la peine d'expliquer pourquoi et comment gérer.
Il en $unwind
va de même pour garder les éléments séparés et non dans des tableaux, et faire le $group
premier vous permet d'obtenir le «décompte» des occurrences de la clé de «regroupement».
L' $first
opérateur utilisé plus tard "garde" cette valeur "count", car il vient d'être "dupliqué" pour chaque valeur présente dans le tableau "tags". C'est de toute façon la même valeur, donc ce n'est pas grave. Choisissez-en un.
Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.
En cas d'infraction, veuillez [email protected] Supprimer.
laisse moi dire quelques mots