如何在MongoDB中按分数区间分组并统计数量?
MongoDB按分数区间分组统计实现方案
你可以通过MongoDB聚合框架完成这个需求,以下是完整的聚合管道代码,以及各阶段的作用说明:
db.collection.aggregate([ // 为每个文档标记对应的等级 { $addFields: { level: { $switch: { branches: [ { case: { $and: [{ $gte: ["$score", 1] }, { $lt: ["$score", 5] }] }, then: "poor" }, { case: { $and: [{ $gte: ["$score", 5] }, { $lt: ["$score", 7] }] }, then: "ok" }, { case: { $and: [{ $gte: ["$score", 7] }, { $lt: ["$score", 8.5] }] }, then: "good" }, { case: { $and: [{ $gte: ["$score", 8.5] }, { $lte: ["$score", 10] }] }, then: "excellent" } ], default: null // 处理不在指定区间的分数,可按需调整 } } } }, // 按等级分组统计数量 { $group: { _id: "$level", count: { $sum: 1 } } }, // 合并统计结果并收集已存在的等级 { $group: { _id: null, stats: { $push: { name: "$_id", count: "$count" } }, allLevels: { $addToSet: "$_id" } } }, // 找出缺失的等级(即没有数据的等级) { $addFields: { missingLevels: { $setDifference: [["excellent", "good", "ok", "poor"], "$allLevels"] } } }, // 为缺失的等级生成count为0的统计条目 { $addFields: { missingStats: { $map: { input: "$missingLevels", as: "level", in: { name: "$$level", count: 0 } } } } }, // 合并所有统计条目,生成最终data数组 { $project: { _id: 0, data: { $concatArrays: ["$stats", "$missingStats"] } } }, // 按指定顺序排序结果(可选,确保顺序符合预期) { $addFields: { data: { $sortArray: { input: "$data", sortBy: { name: { $indexOfArray: [["excellent", "good", "ok", "poor"], "$name"] } } } } } } ])
各阶段详细说明
- $addFields:给每条数据新增
level字段,通过$switch判断分数所属区间,匹配对应的等级标签;不在指定区间的分数会标记为null,你可以根据业务需求调整默认值。 - 第一次$group:以
level为分组键,用$sum:1统计每个等级下的文档数量。 - 第二次$group:把所有分组统计结果合并到
stats数组中,同时用allLevels收集当前存在数据的等级,方便后续识别缺失的等级。 - 缺失等级识别:用
$setDifference对比预定义的完整等级列表和allLevels,找出没有数据的等级。 - 缺失统计生成:用
$map将缺失的等级转换成{name: 等级名, count:0}的格式,保证所有等级都有统计条目。 - 结果合并:用
$concatArrays把已有统计和缺失统计合并,生成最终的data数组,同时去掉无关的_id字段。 - 排序(可选):通过
$sortArray和$indexOfArray,让结果严格按照excellent→good→ok→poor的顺序排列,和你期望的输出格式完全一致。
内容的提问来源于stack exchange,提问作者TheStranger
相关产品推荐
相关产品推荐

