使用Mongoose分组时如何对字段求和并获取预期统计结果?
解决Mongoose分组求和的完整统计问题
看起来你现在的聚合查询只返回了部分日期的统计结果,问题大概率出在两个地方:要么是$match阶段不小心过滤掉了3月31日的那条数据,要么是分组逻辑没有覆盖到你想要的统计维度。我分几种常见的需求场景给你对应的解决方案:
场景1:按日期(年/月/日)统计每日总记录数
如果你想得到所有日期的总记录数(包括只有1条数据的3月31日),可以用下面的聚合管道:
// 替换成你的Model名称 YourModel.aggregate([ // 如果不需要过滤条件,直接删除$match阶段;如果需要过滤,确保条件包含所有要统计的记录 // { $match: { /* 你的过滤条件,比如status的范围等 */ } }, { $group: { _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" }, day: { $dayOfMonth: "$createdAt" } }, count: { $sum: 1 } } }, // 可选:按日期升序排序,让结果更直观 { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1 } } ]) .then(results => { console.log("完整统计结果:", results); }) .catch(err => { console.error("聚合查询出错:", err); });
执行后会得到两条结果:
[ { _id: { year: 2018, month: 3, day: 31 }, count: 1 }, { _id: { year: 2018, month: 4, day: 1 }, count: 2 } ]
场景2:按日期+状态分组,统计每个日期下不同状态的记录数
如果需要更细粒度的统计,比如每天每个status的数量,可以调整$group的_id包含status字段:
YourModel.aggregate([ { $group: { _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" }, day: { $dayOfMonth: "$createdAt" }, status: "$status" }, count: { $sum: 1 } } }, { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1, "_id.status": 1 } } ])
结果会包含三条数据,对应每条记录的状态统计:
[ { _id: { year: 2018, month: 3, day: 31, status: -1 }, count: 1 }, { _id: { year: 2018, month: 4, day: 1, status: 0 }, count: 1 }, { _id: { year: 2018, month: 4, day: 1, status: 2 }, count: 1 } ]
场景3:按日期分组,同时统计每个日期下各状态的数量(结构化展示)
如果希望把每个状态的数量作为单独字段展示(比如一条数据包含当天所有状态的统计),可以用$cond结合$sum实现:
YourModel.aggregate([ { $group: { _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" }, day: { $dayOfMonth: "$createdAt" } }, totalCount: { $sum: 1 }, statusMinus1: { $sum: { $cond: [{ $eq: ["$status", -1] }, 1, 0] } }, status0: { $sum: { $cond: [{ $eq: ["$status", 0] }, 1, 0] } }, status2: { $sum: { $cond: [{ $eq: ["$status", 2] }, 1, 0] } } } }, { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1 } } ])
返回的结果会更结构化:
[ { _id: { year: 2018, month: 3, day: 31 }, totalCount: 1, statusMinus1: 1, status0: 0, status2: 0 }, { _id: { year: 2018, month: 4, day: 1 }, totalCount: 2, statusMinus1: 0, status0: 1, status2: 1 } ]
为什么你之前只得到一条结果?
大概率是这两个原因之一:
$match阶段过滤了数据:检查你的$match条件,是不是不小心排除了3月31日的那条记录(比如时间范围只选了4月1日之后);- 时区问题:MongoDB的日期操作默认使用UTC时间,如果你的业务时间是本地时区,可能导致日期提取错误。可以用
$dateToString指定时区来修正,比如:
_id: { date: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt", timezone: "Asia/Shanghai" } } }
内容的提问来源于stack exchange,提问作者IT_WRU
相关产品推荐
相关产品推荐

