MongoDB 3.4以降の集約フレームワークは、 $reduce
を提供します 追加のパイプラインを必要とせずに合計を効率的に計算する演算子。これを式として使用して、合計評価を返し、 $size
を使用して評価数を取得することを検討してください。 。 $addFields
と一緒に したがって、平均は算術演算子 $divide
を使用して計算できます。 式average = total ratings/number of ratings
のように :
db.collection.aggregate([
{
"$addFields": {
"rating_average": {
"$divide": [
{ // expression returns total
"$reduce": {
"input": "$ratings",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.rating"] }
}
},
{ // expression returns ratings count
"$cond": [
{ "$ne": [ { "$size": "$ratings" }, 0 ] },
{ "$size": "$ratings" },
1
]
}
]
}
}
}
])
サンプル出力
{
"_id" : ObjectId("58ab48556da32ab5198623f4"),
"title" : "The Hobbit",
"ratings" : [
{
"title" : "best book ever",
"rating" : 5.0
},
{
"title" : "good book",
"rating" : 3.5
}
],
"rating_average" : 4.25
}
古いバージョンでは、最初に $unwind
を適用する必要があります ratings
の演算子 最初の集計パイプラインステップとして、最初に配列フィールド。これにより、ratings
が分解されます 各要素のドキュメントを出力するための入力ドキュメントの配列フィールド。各出力ドキュメントは、配列を要素値に置き換えます。
2番目のパイプラインステージは$group
になります 入力ドキュメントを_id
でグループ化する演算子 およびtitle
キー識別子式と目的の$avg
を適用します 平均を計算する各グループへのアキュムレータ式。別のアキュムレータ演算子$push
があります 上記のグループの各ドキュメントに式を適用した結果のすべての値の配列を返すことにより、元の評価配列フィールドを保持します。
パイプラインの最後のステップは、 $project
です。 次に、新しいフィールドratings_average
を追加するなどして、ストリーム内の各ドキュメントの形状を変更する演算子 。
したがって、たとえば、コレクションにサンプルドキュメントがある場合(上などから):
db.collection.insert({
"title": "The Hobbit",
"ratings": [
{
"title": "best book ever",
"rating": 5
},
{
"title": "good book",
"rating": 3.5
}
]
})
評価配列の平均を計算し、値を別のフィールドに投影するにはratings_average
、次の集計パイプラインを適用できます:
db.collection.aggregate([
{
"$unwind": "$ratings"
},
{
"$group": {
"_id": {
"_id": "$_id",
"title": "$title"
},
"ratings":{
"$push": "$ratings"
},
"ratings_average": {
"$avg": "$ratings.rating"
}
}
},
{
"$project": {
"_id": 0,
"title": "$_id.title",
"ratings_average": 1,
"ratings": 1
}
}
])
結果 :
/* 1 */
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}