TLDR;
Moderne udgivelser bør bruge $reduce
med $setUnion
efter den indledende $group
som vist:
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" ] }
}
}
}}
])
Du havde ret i at finde $addToSet
operatør, men når du arbejder med indhold i et array, skal du generelt behandle med $unwind
først. Dette "denormaliserer" array-indgangene og laver i det væsentlige en "kopi" af det overordnede dokument med hver array-indgang som en enkelt værdi i feltet. Det er det, du skal bruge for at undgå den adfærd, du ser uden at bruge det.
Din "optælling" udgør dog et interessant problem, men det løses nemt ved at bruge en "dobbelt afvikling" efter en indledende $group
operation:
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"
}}
])
Den sidste bit med $project
er der også, fordi jeg brugte "midlertidige" navne for hvert af felterne i andre stadier af aggregeringspipelinen. Dette skyldes, at der er en optimering i $project
at "kopierer" felterne fra et eksisterende trin i den rækkefølge, de allerede opstod "før" nogen "nye" felter tilføjes til dokumentet.
Ellers ville output se sådan ud:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
Hvor felterne ikke er i samme rækkefølge, som du måske tror. Trivielt virkelig, men det betyder noget for nogle mennesker, så det er værd at forklare hvorfor, og hvordan man håndterer det.
Så $unwind
gør arbejdet for at holde elementerne adskilt og ikke i arrays, og udfører $group
giver dig først mulighed for at få "tællingen" af forekomsterne af "grupperings"-tasten.
$first
operatør, der senere blev brugt, "beholder" denne "tælle"-værdi, da den lige er blevet "duplikeret" for hver værdi, der findes i "tags"-arrayet. Det er alligevel den samme værdi, så det er ligegyldigt. Bare vælg en.