MongoDB 3.4及更高版本中的聚合框架提供了强大的$reduce
运算符,可高效地计算总数,无需额外的管道。考虑将其作为表达式返回总评分,并使用$size
获取评分数量。结合$addFields
,可以使用算术运算符$divide
计算平均值,公式如下:average = 总评分/评分数量
:
db.collection.aggregate([
{
"$addFields": {
"rating_average": {
"$divide": [
{
"$reduce": {
"input": "$ratings",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.rating"] }
}
},
{
"$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
}
使用旧版本,您需要首先在初始聚合管道步骤上对
ratings
数组字段应用
$unwind
运算符。这将从输入文档中解构
ratings
数组字段,以输出每个元素的文档。每个输出文档都将数组替换为一个元素值。
第二个流水线阶段将是
$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
}
}
])
结果:
{
"result" : [
{
"ratings" : [
{
"title" : "best book ever",
"rating" : 5
},
{
"title" : "good book",
"rating" : 3.5
}
],
"ratings_average" : 4.25,
"title" : "The Hobbit"
}
],
"ok" : 1
}