TLDR;
Rilis modern harus menggunakan $reduce
dengan $setUnion
setelah $group
initial awal seperti yang ditunjukkan:
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" ] }
}
}
}}
])
Anda benar dalam menemukan $addToSet
operator, tetapi ketika bekerja dengan konten dalam array, Anda biasanya perlu memproses dengan $unwind
pertama. Ini "mendenormalisasi" entri array dan pada dasarnya membuat "salinan" dokumen induk dengan setiap entri array sebagai nilai tunggal di bidang. Itulah yang Anda butuhkan untuk menghindari perilaku yang Anda lihat tanpa menggunakannya.
"Hitungan" Anda menimbulkan masalah yang menarik, tetapi mudah diselesaikan melalui penggunaan "penguraian ganda" setelah $group
awal operasi:
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"
}}
])
Bagian terakhir dengan $project
ada juga karena saya menggunakan nama "sementara" untuk masing-masing bidang di tahap lain dari pipa agregasi. Ini karena ada pengoptimalan di $project
bahwa "menyalin" bidang dari tahap yang ada dalam urutan yang sudah muncul "sebelum" bidang "baru" ditambahkan ke dokumen.
Jika tidak, hasilnya akan terlihat seperti:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
Di mana bidangnya tidak dalam urutan yang sama seperti yang Anda kira. Benar-benar sepele, tetapi penting bagi sebagian orang, jadi perlu dijelaskan alasannya, dan cara menanganinya.
Jadi $unwind
melakukan pekerjaan untuk menjaga item terpisah dan tidak dalam array, dan melakukan $group
pertama memungkinkan Anda untuk mendapatkan "hitungan" kemunculan kunci "pengelompokan".
$first
operator kemudian menggunakan "menyimpan" nilai "hitungan" itu, karena baru saja "digandakan" untuk setiap nilai yang ada dalam larik "tag". Itu semua nilainya sama saja jadi tidak masalah. Pilih satu saja.