TLDR;
最新のリリースでは、$reduce
を使用する必要があります $setUnion
を使用 最初の$group
の後 示されているように:
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" ] }
}
}
}}
])
あなたは$addToSet
を見つけるのに正しかった 演算子ですが、配列内のコンテンツを操作する場合は、通常、 $unwind
で処理する必要があります 最初。これにより、配列エントリが「非正規化」され、基本的に、各配列エントリがフィールド内の特異値として親ドキュメントの「コピー」が作成されます。それはあなたがそれを使わずにあなたが見ている行動を避けるためにあなたが必要とするものです。
あなたの「カウント」は興味深い問題を引き起こしますが、最初の $group
の後に「ダブルアンワインド」を使用することで簡単に解決できます 操作:
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"
}}
])
$project
の最後のビット また、集計パイプラインの他のステージの各フィールドに「一時的な」名前を使用したためです。これは、 $project
に最適化があるためです。 これは、既存のステージのフィールドを、「新しい」フィールドがドキュメントに追加される「前」にすでに表示されている順序で「コピー」します。
それ以外の場合、出力は次のようになります。
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
フィールドがあなたが思うかもしれないのと同じ順序ではないところ。些細なことですが、一部の人にとっては重要なので、その理由と処理方法を説明する価値があります。
つまり、 $unwind
アイテムを配列ではなく分離して保持する作業を行い、 $group
を実行します 最初に、「グループ化」キーの発生の「カウント」を取得できます。
$first
演算子は、「タグ」配列に存在するすべての値に対して「複製」されたため、後でその「カウント」値を「保持」します。とにかくそれはすべて同じ値なので、それは問題ではありません。 1つ選んでください。