TLDR;
Moderna utgåvor bör använda $reduce
med $setUnion
efter den initiala $group
som visas:
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 hade rätt när du hittade $addToSet
operator, men när du arbetar med innehåll i en array behöver du vanligtvis bearbeta med $unwind
först. Detta "avnormaliserar" matrisposterna och gör i huvudsak en "kopia" av det överordnade dokumentet med varje matrispost som ett singulär värde i fältet. Det är vad du behöver för att undvika beteendet du ser utan att använda det.
Din "räkning" utgör dock ett intressant problem, men det löses enkelt genom att använda en "dubbel avveckling" efter en första $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 sista biten med $project
finns också där eftersom jag använde "tillfälliga" namn för vart och ett av fälten i andra stadier av aggregeringspipelinen. Detta beror på att det finns en optimering i $project
som "kopierar" fälten från ett befintligt stadium i den ordning de redan dök upp "innan" några "nya" fält läggs till i dokumentet.
Annars skulle utdata se ut så här:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
Där fälten inte är i samma ordning som man kan tro. Trivialt egentligen, men det är viktigt för vissa människor, så värt att förklara varför och hur man hanterar det.
Så $unwind
gör jobbet för att hålla objekten åtskilda och inte i arrayer, och gör $group
låter dig först få "räkningen" av förekomsterna av "gruppering"-nyckeln.
$first
Operatören som senare används "behåller" det "räknevärde" eftersom det precis har "duplicerats" för varje värde som finns i "taggar"-matrisen. Allt har samma värde ändå så det spelar ingen roll. Välj bara en.