MongoDB聚合如何实现FeedbackFinal非空取Grade,否则取FeedbackClient最近3个有效评分均值
实现逻辑说明
你之前的实现存在两个核心偏差:
- 未过滤
DateVoted为null的无效反馈元素 - 未对有效元素按日期降序排序、截取前3条,直接对全量客户端反馈求平均
针对你提到的两种实现思路,优先选择内置数组操作符链式处理,不需要额外将数据PUSH到中间字段,可在单个投影表达式内完成全流程计算,避免多阶段聚合带来的文档膨胀开销,性能更优。
完整聚合投影实现
{ $project: { ProjectId: 1, // 保留其他需要的字段 Grade: { $cond: { // 判断FeedbackFinal是否存在 if: { $ne: ["$FeedbackFinal", null] }, // 存在则直接取最终评分 then: "$FeedbackFinal.Grade", // 不存在则计算客户端有效评分的平均值 else: { $avg: { $map: { // 链式处理客户端反馈数组 input: { $slice: [ // 对有效反馈按日期降序排序 { $sortArray: { input: { // 第一步:过滤出DateVoted不为空的有效反馈 $filter: { input: "$FeedbackClient", as: "feedback", cond: { $ne: ["$$feedback.DateVoted", null] } } }, sortBy: { DateVoted: -1 } } }, // 第二步:截取排序后的前3条最近反馈 3 ] }, // 提取每条反馈的Grade值用于求平均 as: "sortedFeedback", in: "$$sortedFeedback.Grade" } } } } } } }
效果校验
- 对
ProjectId=123的文档:因FeedbackFinal不为空,直接返回4 - 对
ProjectId=456的文档:因FeedbackFinal为null,取按日期降序排列的前3条有效评分(1、5、2),计算平均值为≈2.67 - 若有效反馈不足3条,
$avg会自动对所有现存有效评分求平均,无需额外做数量判断
注意事项
- 当前日期为
YYYY-MM-DD格式的字符串,字典序排序结果和日期排序结果完全一致,不需要额外转成日期类型;如果后续日期格式不统一,需要先通过$toDate转成标准日期类型再做排序 - 该实现完全不需要搭配
$unwind、$group等多阶段聚合操作,单阶段即可完成计算,执行效率远高于拆分为多阶段的实现方式
内容的提问来源于stack exchange,提问作者2Fast4YouBR
相关产品推荐
相关产品推荐

