如何在Mongoose中一次统计同一属性不同值的文档数量
一次查询统计MongoDB中布尔属性的两种状态数量
你可以通过Mongoose的**聚合管道(Aggregation Pipeline)**实现一次查询完成统计,无需两次调用countDocuments。下面提供两种简洁的实现方式:
方法一:分步分组转换格式
// 替换成你的Mongoose模型名 YourModel.aggregate([ // 第一步:按isCompleted的值分组,统计每组数量 { $group: { _id: "$isCompleted", count: { $sum: 1 } } }, // 第二步:将分组结果合并为目标格式 { $group: { _id: null, completed: { $sum: { $cond: { if: { $eq: ["$_id", true] }, then: "$count", else: 0 } } }, notCompleted: { $sum: { $cond: { if: { $eq: ["$_id", false] }, then: "$count", else: 0 } } } } }, // 第三步:移除多余的_id字段 { $project: { _id: 0 } } ]) .then(result => { // 结果示例:{ completed: 4, notCompleted: 6 } console.log(result[0]); }) .catch(err => { console.error("统计失败:", err); });
逻辑说明:
- $group(第一步):按
isCompleted的布尔值分组,计算每组的文档总数,得到类似[{ _id: true, count:4 }, { _id: false, count:6 }]的中间结果。 - $group(第二步):将所有分组数据合并为一个文档,通过
$cond条件判断分别累加completed和notCompleted的数量。 - $project:移除默认生成的
_id字段,得到干净的目标格式。
方法二:用数组转对象简化代码
如果你觉得上面的步骤繁琐,可以用$arrayToObject和$replaceRoot直接生成目标格式:
YourModel.aggregate([ { $group: { _id: "$isCompleted", count: { $sum: 1 } } }, { $group: { _id: null, stats: { $push: { // 将布尔值映射为对应的键名 k: { $cond: { if: "$_id", then: "completed", else: "notCompleted" } }, v: "$count" } } } }, { // 将stats数组转换为对象,作为根文档 $replaceRoot: { newRoot: { $arrayToObject: "$stats" } } } ]) .then(result => { console.log(result[0]); }) .catch(err => { console.error("统计失败:", err); });
处理空状态场景
如果某类状态(比如没有isCompleted: true的文档)不存在,上面的方法会缺失对应的字段。如果需要确保始终返回completed和notCompleted(值为0),可以修改聚合管道:
YourModel.aggregate([ { $group: { _id: "$isCompleted", count: { $sum: 1 } } }, { $group: { _id: null, completed: { $sum: { $cond: { if: { $eq: ["$_id", true] }, then: "$count", else: 0 } } }, notCompleted: { $sum: { $cond: { if: { $eq: ["$_id", false] }, then: "$count", else: 0 } } } } }, { $project: { _id: 0, // 用$ifNull确保字段存在,默认值为0 completed: { $ifNull: ["$completed", 0] }, notCompleted: { $ifNull: ["$notCompleted", 0] } } } ])
内容的提问来源于stack exchange,提问作者Saman
相关产品推荐
相关产品推荐

