如何从MongoDB集合中将每分钟数据转换为每小时粒度数据?
调整MongoDB聚合查询为每小时粒度的实现方案
首先纠正原查询中的一个错误:timestampISO的范围条件写反了,$lt应指向更大的时间戳,$gte指向更小的时间戳,否则会查询不到数据。
要将每分钟粒度的结果转为每小时粒度,核心是通过时间分组+聚合统计实现,具体修改后的聚合管道如下:
mongo_client.db("db") .collection(collection) .aggregate([ // 1. 转换时间戳为长整型,并计算每小时起始时间戳 { $addFields: { timestampISO: { $toLong: "$periodicMessageBase.messageTimestamp" }, // 将毫秒级时间戳截断到每小时起始点(1小时=3600000毫秒) hourlyTimestamp: { $multiply: [ { $floor: { $divide: ["$timestampISO", 3600000] } }, 3600000 ] } }, }, // 2. 过滤目标设备和时间范围(已修正条件顺序) { $match: { deviceId: deviceId, periodicMessageBase: { $exists: true }, timestampISO: { $gte: "1694008207000", // 起始时间戳(小值) $lt: "1695002207000" // 结束时间戳(大值) }, }, }, // 3. 提取需要的字段 { $project: { _id: 0, DeviceID: "$deviceId", HourlyTimestamp: "$hourlyTimestamp", L1_VoltageAngleMean: { $ifNull: [ { $arrayElemAt: ["$periodicMessageBase.vAngle.meanVal", 0] }, 0 ], } }, }, // 4. 按设备+每小时时间戳分组,聚合统计 { $group: { _id: { DeviceID: "$DeviceID", HourlyTimestamp: "$HourlyTimestamp" }, // 计算该小时内L1_VoltageAngleMean的平均值,可根据需求替换为$max/$min/$first/$last等 L1_VoltageAngleMean: { $avg: "$L1_VoltageAngleMean" }, // 可选:统计该小时内的原始数据条数 dataCount: { $sum: 1 } } }, // 5. 整理输出字段格式 { $project: { _id: 0, DeviceID: "$_id.DeviceID", Timestamp: "$_id.HourlyTimestamp", L1_VoltageAngleMean: 1, dataCount: 1 // 不需要可删除 } }, // 6. 按时间降序排序 { $sort: { Timestamp: -1 } } ])
关键改动说明:
- 每小时时间戳计算:通过
$divide将毫秒时间戳除以3600000(1小时的毫秒数),再用$floor取整后乘以3600000,得到当前时间所在小时的起始时间戳(如1694008800000对应某小时的0分0秒)。 - 分组聚合:使用
$group按设备ID和每小时时间戳分组,通过$avg计算该小时内电压角度均值的平均值。如果不需要平均值,可替换为其他聚合操作符:$max:取该小时内的最大值$min:取该小时内的最小值$first:取该小时内最早的一条数据值$last:取该小时内最晚的一条数据值
- 修正时间范围:原查询中
$lt和$gte的数值顺序错误,已调整为正确的时间范围逻辑。
内容的提问来源于stack exchange,提问作者vignesh ramesh
相关产品推荐
相关产品推荐

