MongoDB中按指定时间计算近5分钟数据的温湿度平均值
MongoDB 每日指定时间点温湿度平均值计算方案
针对你需要获取每日6:00、12:00、22:00三个时间点前5分钟内数据的温湿度平均值需求,可以通过MongoDB聚合管道实现,具体查询语句及解释如下:
聚合查询代码
db.sensor_data.aggregate([ // 可选:限定查询时间范围,减少数据处理量,按需调整 { $match: { "acquisition-time": { $gte: ISODate("2022-05-01T00:00:00.000Z"), $lte: ISODate("2022-05-15T23:59:59.000Z") } } }, // 提取日期并生成三个目标时间的基础窗口信息 { $addFields: { date: { $dateToString: { format: "%Y-%m-%d", date: "$acquisition-time" } }, target_windows: [ { target_time: "06:00", start_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 6, minute: 0, second: 0 } }, end_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 6, minute: 0, second: 0 } } }, { target_time: "12:00", start_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 12, minute: 0, second: 0 } }, end_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 12, minute: 0, second: 0 } } }, { target_time: "22:00", start_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 22, minute: 0, second: 0 } }, end_time: { $dateFromParts: { year: { $year: "$acquisition-time" }, month: { $month: "$acquisition-time" }, day: { $dayOfMonth: "$acquisition-time" }, hour: 22, minute: 0, second: 0 } } } ] } }, // 将每个目标窗口的起始时间调整为目标时间前5分钟 { $addFields: { target_windows: { $map: { input: "$target_windows", as: "window", in: { target_time: "$$window.target_time", start_time: { $subtract: ["$$window.start_time", 5 * 60 * 1000] }, end_time: "$$window.end_time" } } } } }, // 展开目标窗口数组,让每个文档对应一个窗口判断 { $unwind: "$target_windows" }, // 筛选出采集时间落在当前窗口内的文档 { $match: { $expr: { $and: [ { $gte: ["$acquisition-time", "$target_windows.start_time"] }, { $lte: ["$acquisition-time", "$target_windows.end_time"] } ] } } }, // 按日期和目标时间分组计算平均值 { $group: { _id: { date: "$date", target_time: "$target_windows.target_time" }, avg_temperature: { $avg: "$temperature" }, avg_humidity: { $avg: "$humidity" }, data_count: { $sum: 1 } // 统计参与计算的数据条数,可选 } }, // 整理输出格式,保留两位小数 { $project: { _id: 0, date: "$_id.date", target_time: "$_id.target_time", avg_temperature: { $round: ["$avg_temperature", 2] }, avg_humidity: { $round: ["$avg_humidity", 2] }, data_count: 1 } }, // 按日期和目标时间排序结果 { $sort: { date: 1, target_time: 1 } } ])
关键阶段解释
- $match(可选):先缩小查询的时间范围,避免处理全量数据,提升效率。
- $addFields(生成基础字段):提取文档的日期字符串,同时生成三个目标时间点的基础时间对象。
- $addFields(调整窗口):通过
$subtract将每个目标时间的窗口起始点向前推5分钟(转换为毫秒计算)。 - $unwind:将包含三个目标窗口的数组展开,让每个文档对应一个窗口的判断条件。
- $match:过滤出采集时间落在当前窗口内的有效数据,确保只有符合规则的数据进入计算。
- $group:按日期和目标时间分组,计算温湿度的平均值,同时统计数据条数用于验证数据覆盖情况。
- $project:优化输出格式,隐藏默认的
_id字段,并将平均值保留两位小数,让结果更易读。 - $sort:对结果按日期和目标时间升序排列,方便查看时序数据。
性能优化建议
- 为
acquisition-time字段创建单字段索引,大幅提升时间范围查询的效率:db.sensor_data.createIndex({ "acquisition-time": 1 })
注意事项
- 若某一天的某个目标时间窗口内没有数据,该分组不会出现在结果中。如果需要强制显示所有日期的所有目标时间(包括无数据的情况),可以预先生成包含所有日期和目标时间的集合,再通过
$lookup关联查询结果。
内容的提问来源于stack exchange,提问作者Abdullah Al Mamun
相关产品推荐
相关产品推荐

