如何使用Mongoose在MongoDB中按天统计近一周的平均值?
用Mongoose实现过去7天每日
value平均值统计 当然可以直接通过Mongoose结合MongoDB的聚合框架搞定这个需求!核心思路是利用聚合管道完成时间范围筛选、按天分组求均值、填充缺失日期、排序生成目标数组这几个步骤,完全不需要在应用层做额外的数据拼接处理。
核心实现步骤
- 筛选时间范围:先确定今日往前推7天的时间区间,只处理这个范围内的文档。
- 按天分组求均值:将
created_at截断到“天”维度,按日期分组计算每天value的平均值。 - 填充缺失日期:如果某一天没有数据,要确保结果数组里对应位置有默认值(比如0),这里通过生成7天的日期序列并左连接分组结果来实现。
- 排序并生成目标数组:按日期从早到晚(上周同一天到今日)排序,最后提取平均值组成数组。
完整代码示例
假设你的Mongoose模型名为Reading,集合名为readings,可以这样写:
const Reading = require('./models/reading'); // 替换成你的模型路径 async function getWeeklyDailyAverages() { const today = new Date(); // 计算一周前的时间点 const oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); const result = await Reading.aggregate([ // 1. 筛选过去7天内的数据 { $match: { created_at: { $gte: oneWeekAgo, $lte: today } } }, // 2. 按天分组,计算每日平均值 { $group: { _id: { $dateTrunc: { date: "$created_at", unit: "day", timezone: "Asia/Shanghai" // 务必根据你的业务时区调整 } }, avgValue: { $avg: "$value" } } }, // 3. 生成过去7天的完整日期序列(用来填充无数据的日期) { $lookup: { from: "readings", // 替换成你的集合名称 let: {}, pipeline: [ { $documents: [{ $range: [0, 7] }] }, { $unwind: "$range" }, { $project: { date: { $dateSubtract: { startDate: today, unit: "day", amount: { $subtract: [6, "$range"] } // 逻辑:比如今天是周一,6天前是上周周一,0天前是今日,正好覆盖7天 } }, _id: 0 } }, { $dateTrunc: { date: "$date", unit: "day", timezone: "Asia/Shanghai" } } ], as: "dateSeries" } }, // 4. 展开日期序列,左连接分组结果 { $unwind: "$dateSeries" }, { $group: { _id: "$dateSeries", avgValue: { $first: { $ifNull: ["$avgValue", 0] } } // 无数据时填充0,可换成null } }, // 5. 按日期升序排序(从上周同一天到今日) { $sort: { _id: 1 } }, // 6. 将平均值收集成数组 { $group: { _id: null, dailyAverages: { $push: "$avgValue" } } }, // 7. 只保留目标数组字段 { $project: { _id: 0, dailyAverages: 1 } } ]); // 返回结果数组,比如[15.2, 16.0, 14.8, ...] return result[0]?.dailyAverages || []; } // 调用示例 getWeeklyDailyAverages().then(averages => console.log(averages));
注意事项
- 时区问题:MongoDB默认存储UTC时间,一定要在
$dateTrunc或$dateToString中指定业务时区,否则会出现日期截断错误(比如国内业务用Asia/Shanghai)。 - 兼容旧版本MongoDB:如果你的MongoDB版本低于5.0(不支持
$dateTrunc),可以用$dateToString替代:_id: { $dateToString: { format: "%Y-%m-%d", date: "$created_at", timezone: "Asia/Shanghai" } } - 缺失值处理:代码中用
0填充无数据的日期,你可以根据需求改成null或者其他默认值。
内容的提问来源于stack exchange,提问作者ALGDB
相关产品推荐
相关产品推荐

