TLDR ;
Les versions modernes doivent utiliser $reduce
avec $setUnion
après le $group
initial comme indiqué :
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 le $addToSet
, mais lorsque vous travaillez avec du contenu dans un tableau, vous devez généralement traiter avec $unwind
première. Cela "dénormalise" les entrées du tableau et fait essentiellement une "copie" du document parent avec chaque entrée du tableau comme une 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 par l'utilisation d'un "double déroulement" après un premier $group
opération :
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 morceau avec $project
est également là parce que j'ai utilisé des noms "temporaires" pour chacun des champs dans d'autres étapes du pipeline d'agrégation. C'est parce qu'il y a une optimisation dans $project
qui "copie" les champs d'une étape existante dans l'ordre dans lequel ils apparaissaient déjà "avant" que de "nouveaux" champs ne soient ajoutés 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 qu'on pourrait le penser. Insignifiant vraiment, mais cela compte pour certaines personnes, donc cela vaut la peine d'expliquer pourquoi et comment gérer.
Alors $unwind
fait le travail pour garder les éléments séparés et non dans des tableaux, et fait le $group
vous permet d'abord d'obtenir le "compte" des occurrences de la clé de "groupement".
Le $first
L'opérateur utilisé plus tard "conserve" cette valeur "count", car il vient d'être "dupliqué" pour chaque valeur présente dans le tableau "tags". C'est tout de même la même valeur de toute façon donc ce n'est pas grave. Choisissez-en un.