如何使用Mongoose按课程评分平均分对集合进行排序?
如何用Mongoose按自定义评分平均分排序Course集合
没问题!我来帮你搞定这个按自定义平均分排序的需求。你的Course集合里用rateCount数组存储1-5星的评分数量,要先通过公式(1*a + 2*b + 3*c + 4*d + 5*e)/(a+b+c+d+e)算出平均分再排序,这得用到MongoDB的聚合框架来动态计算这个派生字段,下面是具体的实现方法和代码示例:
核心思路
因为平均分是基于rateCount数组动态计算的,没法直接用普通的find()方法排序,所以我们需要用聚合管道(Aggregation Pipeline):先添加一个计算好的平均分字段,再基于这个字段排序。
完整实现代码
const Course = mongoose.model('Course', CourseSchema); async function getCoursesSortedByAverageRate() { const sortedCourses = await Course.aggregate([ // 第一步:计算总评分人数和总分 { $addFields: { totalRates: { $sum: "$rateCount" }, totalScore: { $add: [ { $multiply: [1, { $arrayElemAt: ["$rateCount", 0] }] }, // 1星总分 { $multiply: [2, { $arrayElemAt: ["$rateCount", 1] }] }, // 2星总分 { $multiply: [3, { $arrayElemAt: ["$rateCount", 2] }] }, // 3星总分 { $multiply: [4, { $arrayElemAt: ["$rateCount", 3] }] }, // 4星总分 { $multiply: [5, { $arrayElemAt: ["$rateCount", 4] }] } // 5星总分 ] } } }, // 第二步:计算平均分,处理总评分为0的边界情况(避免除以0) { $addFields: { averageRate: { $cond: { if: { $eq: ["$totalRates", 0] }, then: 0, else: { $divide: ["$totalScore", "$totalRates"] } } } } }, // 第三步:按平均分降序排序(升序用1) { $sort: { averageRate: -1 } }, // 可选:移除计算过程中用到的临时字段(如果不需要返回) { $project: { totalRates: 0, totalScore: 0 } } ]); return sortedCourses; }
关键部分解释
$arrayElemAt:用来获取rateCount数组中对应位置的元素(数组索引从0开始,对应1-5星的评分数量)$multiply+$add:按照你的公式计算出所有评分的总分$sum:统计总评分人数(所有星数的评分数量之和)$cond:处理总评分为0的特殊情况,直接返回0,避免出现除以0的错误$sort:基于计算出的averageRate字段排序,-1代表降序(高分在前),1代表升序(低分在前)
额外技巧:添加虚拟字段方便单个查询
如果你希望在查询单个课程文档时也能直接获取平均分,可以给Schema添加虚拟字段:
// 定义虚拟字段averageRate CourseSchema.virtual('averageRate').get(function() { const totalRates = this.rateCount.reduce((sum, count) => sum + count, 0); if (totalRates === 0) return 0; const totalScore = this.rateCount[0] * 1 + this.rateCount[1] * 2 + this.rateCount[2] * 3 + this.rateCount[3] * 4 + this.rateCount[4] * 5; return totalScore / totalRates; }); // 让虚拟字段在JSON/Object输出中可见 CourseSchema.set('toJSON', { virtuals: true }); CourseSchema.set('toObject', { virtuals: true });
注意:虚拟字段是在客户端计算的,不能直接用于MongoDB的批量排序,批量排序还是得用前面的聚合管道方案。
内容的提问来源于stack exchange,提问作者FlowerSun
相关产品推荐
相关产品推荐

