2017アップデート
そのようなよくできた質問は、現代の回答に値します。要求された種類の配列フィルタリングは、実際には、$match
を介して3.2以降の最新のMongoDBリリースで実行できます。 および$project
パイプラインステージは、元のプレーンクエリ操作が意図するものとよく似ています。
db.accounts.aggregate([
{ "$match": {
"email" : "[email protected]",
"groups": {
"$elemMatch": {
"name": "group1",
"contacts.localId": { "$in": [ "c1","c3", null ] }
}
}
}},
{ "$addFields": {
"groups": {
"$filter": {
"input": {
"$map": {
"input": "$groups",
"as": "g",
"in": {
"name": "$$g.name",
"contacts": {
"$filter": {
"input": "$$g.contacts",
"as": "c",
"cond": {
"$or": [
{ "$eq": [ "$$c.localId", "c1" ] },
{ "$eq": [ "$$c.localId", "c3" ] }
]
}
}
}
}
}
},
"as": "g",
"cond": {
"$and": [
{ "$eq": [ "$$g.name", "group1" ] },
{ "$gt": [ { "$size": "$$g.contacts" }, 0 ] }
]
}
}
}
}}
])
これは$filter
を利用します および$map
演算子は、条件を満たす場合にのみ配列から要素を返すため、$unwind
を使用するよりもパフォーマンスがはるかに優れています。 。パイプラインステージは、.find()
からの「query」と「project」の構造を効果的に反映しているため 操作、ここでのパフォーマンスは基本的にそのような操作と同等です。
「ドキュメント間」で実際に作業することを意図している場合は注意してください 「1つ」ではなく「複数の」ドキュメントから詳細をまとめるには、通常、何らかのタイプの$unwind
が必要になります。 これを行うための操作。これにより、「グループ化」のために配列アイテムにアクセスできるようになります。
これが基本的なアプローチです:
db.accounts.aggregate([
// Match the documents by query
{ "$match": {
"email" : "[email protected]",
"groups.name": "group1",
"groups.contacts.localId": { "$in": [ "c1","c3", null ] },
}},
// De-normalize nested array
{ "$unwind": "$groups" },
{ "$unwind": "$groups.contacts" },
// Filter the actual array elements as desired
{ "$match": {
"groups.name": "group1",
"groups.contacts.localId": { "$in": [ "c1","c3", null ] },
}},
// Group the intermediate result.
{ "$group": {
"_id": { "email": "$email", "name": "$groups.name" },
"contacts": { "$push": "$groups.contacts" }
}},
// Group the final result
{ "$group": {
"_id": "$_id.email",
"groups": { "$push": {
"name": "$_id.name",
"contacts": "$contacts"
}}
}}
])
これは、.find()
の基本的な投影機能である複数の一致に対する「配列フィルタリング」です。 できません。
「ネストされた」配列があるため、 $unwind
を処理する必要があります 2回。他の操作と一緒に。