MongoDB按条件计算活动时间差:统计总时长、暂停时长等
解决方案:MongoDB聚合管道计算活动时间
假设你的集合文档结构如下(示例):
{ "_id": ObjectId("65d2f1b7a1b2c3d4e5f6a7b8"), "Log": [ { "status": "Start", "time": ISODate("2024-01-01T09:00:00Z") }, { "status": "Hold", "time": ISODate("2024-01-01T09:30:00Z") }, { "status": "Holdrelease", "time": ISODate("2024-01-01T10:15:00Z") }, { "status": "pause", "time": ISODate("2024-01-01T11:00:00Z") }, { "status": "pauserelease", "time": ISODate("2024-01-01T11:20:00Z") }, { "status": "Hold", "time": ISODate("2024-01-01T11:40:00Z") }, { "status": "Holdrelease", "time": ISODate("2024-01-01T11:50:00Z") }, { "status": "Finish", "time": ISODate("2024-01-01T12:00:00Z") } ] }
使用以下聚合管道计算所需时间:
db.yourCollection.aggregate([ // 提取StartTime和FinishTime,同时保留完整Log数组 { $addFields: { startTime: { $first: { $filter: { input: "$Log", cond: { $eq: ["$$this.status", "Start"] } } }.time }, finishTime: { $first: { $filter: { input: "$Log", cond: { $eq: ["$$this.status", "Finish"] } } }.time } } }, // 计算总耗时totalTime(毫秒) { $addFields: { totalTime: { $subtract: ["$finishTime", "$startTime"] } } }, // 遍历Log数组,累计holdTime和pauseTime { $addFields: { timeStats: { $reduce: { input: "$Log", initialValue: { holdTime: 0, pauseTime: 0, lastHoldTime: null, lastPauseTime: null }, in: { holdTime: { $cond: [ { $eq: ["$$this.status", "Holdrelease"] }, { $add: ["$$value.holdTime", { $subtract: ["$$this.time", "$$value.lastHoldTime"] }] }, "$$value.holdTime" ] }, pauseTime: { $cond: [ { $eq: ["$$this.status", "pauserelease"] }, { $add: ["$$value.pauseTime", { $subtract: ["$$this.time", "$$value.lastPauseTime"] }] }, "$$value.pauseTime" ] }, lastHoldTime: { $cond: [ { $eq: ["$$this.status", "Hold"] }, "$$this.time", "$$value.lastHoldTime" ] }, lastPauseTime: { $cond: [ { $eq: ["$$this.status", "pause"] }, "$$this.time", "$$value.lastPauseTime" ] } } } } } }, // 提取holdTime、pauseTime并计算workTime { $addFields: { holdTime: "$timeStats.holdTime", pauseTime: "$timeStats.pauseTime", workTime: { $subtract: ["$totalTime", { $add: ["$timeStats.holdTime", "$timeStats.pauseTime"] }] } } }, // 保留需要的字段(可选) { $project: { _id: 1, totalTime: 1, holdTime: 1, pauseTime: 1, workTime: 1, // 如果需要保留原始Log可以加上:Log: 1 } } ])
关键逻辑说明:
- 提取StartTime/FinishTime:用
$filter从Log数组中筛选出对应状态的条目,再取时间(假设每个文档只有一个Start和一个Finish) - 计算totalTime:直接用Finish时间减去Start时间,结果是毫秒数
- 累计Hold/Pause时长:用
$reduce遍历Log数组,记录上一次Hold/pause的时间,当遇到对应的release状态时,计算时长并累计到总时长中 - 计算workTime:总时长减去Hold和Pause的总时长
注意事项:
- 确保每个
Hold都有对应的Holdrelease,每个pause都有对应的pauserelease,否则未匹配的状态不会被计入时长 - 如果需要转换为秒/分钟,可以在最后添加阶段用
$divide(比如{ $divide: ["$totalTime", 1000] }转为秒) - 如果文档中可能存在多个Start/Finish,需要根据业务逻辑调整筛选方式(比如取最早的Start和最晚的Finish)
内容的提问来源于stack exchange,提问作者Sachin ganeshkar
相关产品推荐
相关产品推荐

