如何在MongoDB中按月度日期排序集合并生成含数据的月度日期聚合数组
MongoDB聚合管道实现指定月份每日支出统计
要实现生成指定月份的每日支出数组(包含当月所有日期,无支出日期对应空数组),可以通过以下聚合管道完成:
核心思路
- 筛选目标月份的支出数据
- 按日期分组,归集每天的支出记录
- 生成当月所有日期的完整序列
- 将完整日期序列与分组后的支出数据做左连接,补全无支出日期的空数组
完整聚合管道代码
db.expenses.aggregate([ // 筛选2023年10月的支出(按需修改日期范围) { $match: { createdAt: { $gte: ISODate("2023-10-01T00:00:00Z"), $lt: ISODate("2023-11-01T00:00:00Z") } } }, // 按日分组,收集当天所有支出 { $group: { _id: { $dateToString: { format: "%d", date: "$createdAt" } }, expenses: { $push: { title: "$title", value: "$value", createdAt: { $dateToString: { format: "%Y-%m-%dT%H:%M:%S.%LZ", date: "$createdAt" } } } } } }, // 聚合所有分组数据,同时计算当月总天数 { $group: { _id: null, dailyExpenses: { $push: { day: "$_id", expenses: "$expenses" } }, monthDays: { $max: { $dayOfMonth: ISODate("2023-10-01T00:00:00Z") } } } }, // 生成当月所有日期的两位数字符串(如'01'、'15') { $project: { _id: 0, dailyExpenses: 1, allDays: { $map: { input: { $range: [1, { $add: ["$monthDays", 1] }] }, as: "dayNum", in: { $cond: [ { $lt: ["$$dayNum", 10] }, { $concat: ["0", { $toString: "$$dayNum" }] }, { $toString: "$$dayNum" } ] } } } } }, // 匹配日期与支出数据,无支出则返回空数组 { $project: { result: { $map: { input: "$allDays", as: "day", in: { day: "$$day", expenses: { $ifNull: [ { $arrayElemAt: ["$dailyExpenses.expenses", { $indexOfArray: ["$dailyExpenses.day", "$$day"] }] }, [] ] } } } } } }, // 输出最终结果数组 { $replaceRoot: { newRoot: "$result" } } ])
关键细节说明
- 日期筛选:用
$gte当月第一天、$lt下月第一天的方式,避免时区转换导致的日期偏差。 - 日期格式化:通过
$dateToString将日期转为两位日份字符串,保证和生成的日期序列格式一致。 - 空数组补全:利用
$indexOfArray查找对应日期的支出数据,找不到时用$ifNull返回空数组,确保每个日期都有对应的记录。
如果需要动态指定月份,只需修改$match和monthDays计算中的日期参数即可,比如从应用层传入目标月份的起始日期。
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

