MongoDB按独立日期范围聚合子字段,实现多时间维度统计的方法
MongoDB聚合查询:按多日期范围统计各Action的总和
你完全不需要依赖mapReduce!用MongoDB的聚合管道就能轻松实现你想要的效果,而且效率更高。我来帮你调整查询逻辑,实现按全时段、最近7/30/90天统计每个action的总和,并且输出你期望的结构。
核心思路
- 先定位目标
_id的文档(把$match放在最前面,减少后续处理的数据量) - 计算出各个日期范围的阈值(比如7天前的日期)
- 对每个action数组,分别筛选不同日期范围的元素并求和
- 最后重新组织输出结构,匹配你想要的格式
完整聚合查询语句
db.collection.aggregate([ // 第一步:先筛选目标文档,减少后续处理量 { $match: { _id: "12345678" } }, // 第二步:计算各个日期范围的阈值(若date已是ISODate,可跳过后续的$dateFromString转换) { $addFields: { last7DaysDate: { $subtract: [new Date(), 7*24*60*60*1000] }, last30DaysDate: { $subtract: [new Date(), 30*24*60*60*1000] }, last90DaysDate: { $subtract: [new Date(), 90*24*60*60*1000] } } }, // 第三步:对每个action计算各时间段的总和 { $addFields: { // 处理action1 action1_stats: { alltime: { $sum: "$action1.value" }, last7Days: { $sum: { $map: { input: { $filter: { input: "$action1", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last7DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last30Days: { $sum: { $map: { input: { $filter: { input: "$action1", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last30DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last90Days: { $sum: { $map: { input: { $filter: { input: "$action1", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last90DaysDate" ] } } }, as: "item", in: "$$item.value" } } } }, // 处理action2,逻辑与action1一致 action2_stats: { alltime: { $sum: "$action2.value" }, last7Days: { $sum: { $map: { input: { $filter: { input: "$action2", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last7DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last30Days: { $sum: { $map: { input: { $filter: { input: "$action2", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last30DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last90Days: { $sum: { $map: { input: { $filter: { input: "$action2", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last90DaysDate" ] } } }, as: "item", in: "$$item.value" } } } }, // 处理action3,逻辑与action1一致 action3_stats: { alltime: { $sum: "$action3.value" }, last7Days: { $sum: { $map: { input: { $filter: { input: "$action3", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last7DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last30Days: { $sum: { $map: { input: { $filter: { input: "$action3", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last30DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last90Days: { $sum: { $map: { input: { $filter: { input: "$action3", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last90DaysDate" ] } } }, as: "item", in: "$$item.value" } } } }, // 处理action4,逻辑与action1一致 action4_stats: { alltime: { $sum: "$action4.value" }, last7Days: { $sum: { $map: { input: { $filter: { input: "$action4", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last7DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last30Days: { $sum: { $map: { input: { $filter: { input: "$action4", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last30DaysDate" ] } } }, as: "item", in: "$$item.value" } } }, last90Days: { $sum: { $map: { input: { $filter: { input: "$action4", cond: { $gte: [ { $dateFromString: { dateString: "$$this.date" } }, "$last90DaysDate" ] } } }, as: "item", in: "$$item.value" } } } } } }, // 第四步:重新组织输出结构,匹配你想要的格式 { $project: { _id: 1, action1: "$action1_stats", action2: "$action2_stats", action3: "$action3_stats", action4: "$action4_stats", // 移除临时生成的日期阈值字段 last7DaysDate: 0, last30DaysDate: 0, last90DaysDate: 0 } } ])
关键细节说明
- 日期类型转换:因为你的
date字段是字符串格式,所以用$dateFromString将其转换为MongoDB可识别的日期类型,才能和计算出的日期阈值正确比较。如果你的date已是ISODate类型,可以直接去掉$dateFromString,用$$this.date直接比较。 - $match的位置:将
$match放在聚合管道最开头,先过滤出目标文档,避免处理无关数据,大幅提升查询效率。 - 复用计算结果:通过
$addFields只计算一次日期阈值,后续所有action的筛选都复用这些值,避免重复计算。 - 筛选求和逻辑:先用
$filter筛选符合日期范围的元素,再用$map提取元素的value,最后用$sum求和,实现各时间段的统计。
内容的提问来源于stack exchange,提问作者Tanmoy Bhattacharjee
相关产品推荐
相关产品推荐

