$filter
オペレータが別のパイプラインステージはありません。配列としてプロパティを返すだけです。最高の$avg
に引数として$group
に直接このケースでは使われています:
db.restaurants.aggregate([
{ '$group': {
'_id': '$name',
'avg': {
'$avg': {
'$avg': {
'$map': {
'input': {
'$filter': {
'input': '$grades',
'as': 'grade',
'cond': { '$eq': [ '$$grade.grade', 'A' ] }
}
},
'as': 'grade',
'in': '$$grade.score'
}
}
}
}
}},
{ '$sort': { 'avg': 1 } }
])
はまた、唯一の"score"
値を抽出し、「二回」と表示され$avg
、それらを養うために$map
を適用し、一度あることは、「作成します文書内の平均値、第2に、グループ化キーの「平均アキュムレータ」である。質問に示されたデータについては
は、あなたが得る:
グレード「A」でマークされたエントリのみから平均スコアである
{
"_id" : "Morris Park Bake Shop",
"avg" : 6.75
}
。
は、興味深いことに、これは単一のドキュメントで正常に動作しますが、https://raw.githubusercontent.com/mongodb/docs-assets/primer-dataset/primer-dataset.jsonから完全なデータセットに適用される場合、これは実際には複数のドキュメントの上に蓄積されていない任意の$avg
を得るためnull
値を生産しています。単に文書にフィルタアレイからの平均値を加算
が正常に動作:
db.restaurants.aggregate([
{ "$addFields": {
"average": {
"$avg": {
"$map": {
"input": {
"$filter": {
"input": "$grades",
"as": "g",
"cond": { "$eq": [ "$$g.grade", "A" ] }
}
},
"as": "g",
"in": "$$g.score"
}
}
}
}}
])
複数のドキュメント上に蓄積したように。 "cuisine"
のためのすなわち:
db.restaurants.aggregate([
{ '$group': {
'_id': '$cuisine',
'avg': {
'$avg': {
'$avg': {
'$map': {
'input': {
'$filter': {
'input': '$grades',
'as': 'g',
'cond': { '$eq': [ '$$g.grade', 'A' ] }
}
},
'as': 'g',
'in': '$$g.score'
}
}
}
}
}},
{ '$sort': { 'avg': 1 } }
])
これは元々述べたと明らかに値が実際に複数のドキュメントで発生する「ためにグループ化」されたときに行うように動作するように意図されています。
悲しいことに、いくつの文書がグループ化されていても適用できる唯一の信頼できる方法は、依然として$unwind
です。一貫性のある結果で動作します。この一方で
:本当に現代のリリースでは必要ありませんどの
db.restaurants.aggregate([
{ "$match": { "grades.grade": "A" } },
{ "$unwind": "$grades" },
{ "$match": { "grades.grade": "A" } },
{ "$group": {
"_id": "$name",
"score": { "$avg": "$grades.score" }
}},
{ "$sort": { "score": -1 } }
])
最適なものをやると、実際に「リンゴとリンゴを」比較することはプレフィルタすることですいずれかが$sort
は通常に適用される。また
db.restaurants.aggregate([
{ '$match': { 'grades.grade': 'A' } },
{ '$group': {
'_id': '$name',
'value': {
'$avg': {
'$avg': {
'$map': {
'input': {
'$filter': {
'input': '$grades',
'as': 'g',
'cond': { '$eq': [ '$$g.grade', 'A' ] }
}
},
'as': 'g',
'in': '$$g.score'
}
}
}
}
}},
{ "$sort": { "value": -1 } }
])
:おそらく初期の段階で$match
で基準に一致する配列要素を持つことができる唯一の人のため「のドキュメント」 「負」または「降順」の順番で、最初に最大値を示します。少なくとも、データを検査して一般的な集約をするときには、最も意味があります。
これよりも短いか、おそらく「あまり混乱しない」とは、が「より良い」という意味ではありません。ここにあります。 $filter
と$map
操作を$group
パイプライン内に記述する理由は、$unwind
の処理が非常にコストがかかるためです。
$unwind
を使用すると、配列メンバーごとにドキュメント全体のコピーが作成されます。これは、一般に、処理するドキュメントの数が大幅に増加するため、処理にかなりの時間を要します。
したがって、「短い方が良い」という実際のケースは、実際には「パイプライン段階が少ない」ことです。処理するドキュメントの数を膨らませないことで、すべての使用量をすべて削除して処理します。$unwind
あなたは$unwind
で処理するときに、他の例では、任意の空の配列は、その後、他の後続$match
そこにフィルタリングすることは何もどこ処理する文書から除去することになるので$group
前$match
に追加するための理由があります"A"
のグレードはなく、グレードはあったが一致するものは"A"
と一致していなかったドキュメントもそこで削除されていました。
その引数の空の配列から$avg
に返される値ですので、そう$map
と$filter
を使用して、これらの文書はnull
を返します。もちろん、最初の条件が「文書」に一致する条件が含まれていなければならない場合、最初は空であるか、または「フィルタリングされた空の」配列は処理の最初から削除されているため考慮されません。それ以降の任意の条件に対して有効になります文書だけが唯一のものになるように、「フィルタリング」のいくつかの程度を含む任意の集計作業の黄金のルールは、常に$match
非常に最初のパイプラインステージとしてにあるということで
選択された。これはまた、それが自分のものであることをかなりスピードアップします。
NOTE: This caused me some considerable panic in a tired state because of the null
values returned. It should be noted that the "usual" application of any $group
operation is typically to accumulate and "reduce" results considerably.
The "$name"
field chosen in the question is pretty much unique for each document in the sample dataset obtained from the MongoDB documentation samples. A more realistic "grouping" sample would be to use "$cuisine"
from the data, which actually accumulates "across documents" for which you typically use
私は理論だと思うが、これを実行したときに、私はこのエラーを取得[OK]:例外:無効な演算子「$の平均」 – user3174311
user3174311 @あなたは私はあなたが、あなたがする必要があるすべてをしたと思うどこからデータを取得した場合doはコピー&ペーストです。データソースに注目すると、私はいくつかの奇妙な動作に気がついたので、実際に何らかの調査を行っていました。この –
についての答えにメモを追加しました。最後の例では、構文がさらにはっきりしています。ありがとうございます。 – user3174311