猫鼬返回按子文档中的字段分组的值的平均值



我正在尝试使用 express/mongoose 构建一种 yelp 克隆,并且需要能够返回一个包含每个评级类别(例如:全球、位置、食物和氛围(平均分数的对象,每个类别来自不同的评论子文档。示例餐厅看起来像这样(我删除了不相关的字段(:

{ 
name: 'Test Restaurant',
reviews: [ 
{ 
_id: 5e42c12e903eac188077dca5, 
rating: {
global: 10,
location: 5,
food: 8,
ambient: 6
} 
},
{ 
_id: 5e42c12e903eac188077dca6, 
rating: {
global: 5,
location: 6,
food: 4,
ambient: 2
} 
},
{ 
_id: 5e42c12e903eac188077dca7, 
rating: {
global: 9,
location: 3,
food: 5,
ambient: 1
} 
},
]
}

到目前为止,我已经能够使用以下虚拟方法做到这一点,但是我想如果评论数量增长到足够大,这将迅速变得低效:

restaurantSchema.virtual("averageRatings").get(function() {
const restaurant = this;
const ratings = restaurant.reviews.map(review => review.rating);
const ratingsArrays = {};
const averageRatings = {};
const categories = [
"global",
"food",
"ambient",
"location"
];
//Loop for every category, create new array with the ratings from each review per category, and filter out null ratings
categories.forEach(category => {
ratingsArrays[category] = ratings
.map(rating => rating[category])
.filter(value => value != null);
//Calculate average for each category, and return undefined where there are not ratings
averageRatings[category] =
ratingsArrays[category].reduce((acc, current) => acc + current, 0) /
ratingsArrays[category].length || undefined;
});
return averageRatings;
});

现在,我已经看到了更有效/更正确的方法是使用 MongoDB 聚合框架,但即使我已经浏览了手册并针对特定情况找到了一些非常好的答案,但我无法在这种特殊情况下完成它。

可以帮助我找到一个可以使用的大致管道吗?您是否知道有什么资源可以以比官方手册更友好的方式学习MongoDB查询/聚合语法(SQL如下:https://sqlbolt.com/(?

使用聚合框架,您可以动态计算读取rating键的平均值。尝试从$objectToArray开始,然后按检索到的键分组(k(。最终,您需要运行反向操作,$arrayToObject:

db.collection.aggregate([
{
$unwind: "$reviews"
},
{
$project: {
values: { $objectToArray: "$reviews.rating" }
}
},
{
$unwind: "$values"
},
{
$group: {
_id: { _id: "$_id", k: "$values.k" },
sum: { $sum: "$values.v" },
count: { $sum: 1 }
}
},
{
$group: {
_id: "$_id._id",
averages: { $push: { k: "$_id.k", v: { $divide: [ "$sum", "$count" ] } } }
}
},
{
$project: {
avgReviews: { $arrayToObject: "$averages" }
}
}
])

蒙戈游乐场

最新更新