探している人のための注釈-外国人カウント
最初に回答されたものよりも少し良いのは、実際に新しい形式の $ lookup
MongoDB3.6から。これにより、後続のフィルタリングとカウントのために「配列」を返すのではなく、「サブパイプライン」式内で「カウント」を実際に実行できます。また、 $ unwind
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"let": { "id": "$_id" },
"pipeline": [
{ "$match": {
"originalLink": "",
"$expr": { "$eq": [ "$$id", "$_id" ] }
}},
{ "$count": "count" }
],
"as": "linkCount"
}},
{ "$addFields": {
"linkCount": { "$sum": "$linkCount.count" }
}}
])
元の質問が求めていたものではなく、以下の回答の一部が現在最も最適な形式になっています。もちろん、 $ lookup
「一致した数」に減らされますのみ 「一致したすべてのドキュメント」の代わりに。
オリジナル
これを行う正しい方法は、 "linkCount"
を追加することです。 $ group
ステージと $ first
$ unwind
$lookup<の結果である配列で処理されました。 / code>
:
すべての詳細
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$unwind": "$link" },
{ "$match": { "link.originalLink": "" } },
{ "$group": {
"_id": "$_id",
"partId": { "$first": "$partId" },
"link": { "$push": "$link" },
"linkCount": {
"$sum": {
"$size": {
"$ifNull": [ "$link.linkHistory", [] ]
}
}
}
}}
])
生産物:
{
"_id" : ObjectId("594a6c47f51e075db713ccb6"),
"partId" : "f56c7c71eb14a20e6129a667872f9c4f",
"link" : [
{
"_id" : ObjectId("594b96d6f51e075db67c44c9"),
"originalLink" : "",
"emailGroupId" : ObjectId("594a6c47f51e075db713ccb6"),
"linkHistory" : [
{
"_id" : ObjectId("594b96f5f51e075db713ccdf")
},
{
"_id" : ObjectId("594b971bf51e075db67c44ca")
}
]
}
],
"linkCount" : 2
}
partIdでグループ化
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$unwind": "$link" },
{ "$match": { "link.originalLink": "" } },
{ "$group": {
"_id": "$partId",
"linkCount": {
"$sum": {
"$size": {
"$ifNull": [ "$link.linkHistory", [] ]
}
}
}
}}
])
生産
{
"_id" : "f56c7c71eb14a20e6129a667872f9c4f",
"linkCount" : 2
}
$ unwind コード>
次に、 $ match
これは、MongoDBがこの順序で発行されたときにパイプラインを実際に処理する方法が原因です。これは、 $ lookup
に発生することです。
示されているように、 "explain"
操作からの出力:
{
"$lookup" : {
"from" : "link",
"as" : "link",
"localField" : "_id",
"foreignField" : "emailGroupId",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"originalLink" : {
"$eq" : ""
}
}
}
},
{
"$group" : {
$ group
でパーツを残します
その出力では、他の2つのパイプラインステージが「消える」ことを示しています。これは、それらがに「ロールアップ」されているためです。 $ lookup
示されているパイプラインステージ。これは実際、MongoDBが $ lookup
親ドキュメントの配列に。
または、次のように操作を記述できます。
すべての詳細
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$addFields": {
"link": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"linkCount": {
"$sum": {
"$map": {
"input": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"as": "l",
"in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
}
}
}
}}
])
partIdでグループ化
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$addFields": {
"link": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"linkCount": {
"$sum": {
"$map": {
"input": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"as": "l",
"in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
}
}
}
}},
{ "$unwind": "$link" },
{ "$group": {
"_id": "$partId",
"linkCount": { "$sum": "$linkCount" }
}}
])
これは同じ出力ですが、という点で、最初のクエリとは「異なります」 $ filter
ここでは、すべての「後に」適用されます $ lookup
の結果
親ドキュメントの新しい配列に返されます。
したがって、パフォーマンスの観点からは、実際には最初の方法で実行する方が効果的であり、「フィルタリング前」に16MBのBSON制限を超える可能性のある大きな結果セットに移植することもできます。
興味のある方への補足として、MongoDBの将来のリリース(おそらく3.6以降)では、 $ replaceRoot
$ addFields
の代わりに
新しい$mergeObjects
を使用します パイプライン演算子。これの利点は「ブロック」として、「filtered」
を宣言できることです。 $ let
を介した変数としてのコンテンツ
、つまり、同じ $filterを記述する必要はありません。
「2回」:
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$$ROOT",
{ "$let": {
"vars": {
"filtered": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
}
},
"in": {
"link": "$$filtered",
"linkCount": {
"$sum": {
"$map": {
"input": "$$filtered.linkHistory",
"as": "lh",
"in": { "$size": { "$ifNull": [ "$$lh", [] ] } }
}
}
}
}
}}
]
}
}}
])
それでも、このような「フィルタリングされた」 $lookup<を実行するための最良の方法/ code>
現時点では、 $unwind<を使用した操作は「まだ」です。 / code>
次に、 $ match
パターン、$にクエリ引数を提供できるようになるまでルックアップ
直接。