TLDR;
Moderne Versionen sollten $reduce
verwenden mit $setUnion
nach dem anfänglichen $group
wie gezeigt:
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" ] }
}
}
}}
])
Sie hatten Recht, als Sie $addToSet
gefunden haben -Operator, aber wenn Sie mit Inhalten in einem Array arbeiten, müssen Sie im Allgemeinen mit $unwind
verarbeiten Erste. Dadurch werden die Array-Einträge "denormalisiert" und im Wesentlichen eine "Kopie" des übergeordneten Dokuments mit jedem Array-Eintrag als Einzelwert im Feld erstellt. Das ist es, was Sie brauchen, um das Verhalten zu vermeiden, das Sie sehen, ohne es zu verwenden.
Ihre "Zählung" wirft jedoch ein interessantes Problem auf, das jedoch leicht durch die Verwendung einer "doppelten Abwicklung" nach einer anfänglichen $group
gelöst werden kann Betrieb:
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"
}}
])
Das letzte Stückchen mit $project
ist auch da, weil ich "vorübergehende" Namen für jedes der Felder in anderen Phasen der Aggregationspipeline verwendet habe. Dies liegt daran, dass es eine Optimierung in $project
gibt das die Felder aus einer bestehenden Stufe in der Reihenfolge "kopiert", in der sie bereits erschienen sind, "bevor" irgendwelche "neuen" Felder zum Dokument hinzugefügt werden.
Andernfalls würde die Ausgabe so aussehen:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
Wo die Felder nicht in der gleichen Reihenfolge sind, wie Sie vielleicht denken. Eigentlich trivial, aber für manche Leute ist es wichtig, also lohnt es sich zu erklären, warum und wie man damit umgeht.
Also $unwind
erledigt die Arbeit, um die Elemente getrennt und nicht in Arrays zu halten, und erledigt die $group
ermöglicht Ihnen zunächst, die "Anzahl" der Vorkommen des "Gruppierungs"-Schlüssels zu erhalten.
Der $first
Der später verwendete Operator "behält" diesen "count"-Wert, da er einfach für jeden im "tags"-Array vorhandenen Wert "dupliziert" wurde. Es ist sowieso alles derselbe Wert, also spielt es keine Rolle. Wählen Sie einfach eine aus.