如何在MongoDB中实现自动计算字段,自动生成工单duration时长?
实现方案说明
你要实现duration自动计算有两种最优方案,可根据你使用的MongoDB版本选择:
方案1:更新时原子计算(兼容MongoDB 4.2+,无需改表结构)
这是最通用的方案,利用MongoDB 4.2开始支持的更新操作传入聚合管道的特性,直接在单次更新请求里引用已有time_started字段计算差值,全程原子操作,没有并发一致性问题,也不需要额外的查询请求。
修改后的代码如下:
router.post('/completed', function (req, res) { const time_completed = req.body.time_completed const workorder_id = req.body.workorder_id db.collection('workorders').updateOne( { _id: ObjectId(workorder_id) }, // 用数组包裹表示使用聚合管道更新,可以引用文档现有字段 [ { $set: { time_completed: time_completed, // 计算时间差,单位为毫秒,如需其他单位可自行转换 duration: { $subtract: [time_completed, "$time_started"] } // 如果是MongoDB 5.0+,也可以用更直观的$dateDiff指定单位,比如返回分钟数: // duration: { $dateDiff: { startDate: "$time_started", endDate: time_completed, unit: "minute" } } } } ], function (err, result) { if (err) throw err res.send('Updated') } ) });
注意:你原代码里集合名写的是变量
workorder,应该是拼写错误,正确集合名是workorders,请自行核对修正。
方案2:使用MongoDB内置自动计算字段(兼容MongoDB 5.0+,无需修改业务代码)
如果你的MongoDB版本在5.0以上,可以直接给workorders集合设置持久化计算列,后续任何更新time_completed的操作都会自动触发duration的重新计算,完全不用修改接口代码。
创建计算字段的命令示例:
db.runCommand({ collMod: "workorders", validator: { $jsonSchema: { bsonType: "object", properties: { duration: { bsonType: "number", // 定义自动计算规则 description: "自动计算的工单处理时长,单位毫秒", default: { $subtract: ["$time_completed", "$time_started"] }, persistent: true } } } } })
设置完成后你原有的接口代码不需要任何改动,只要更新time_completed,duration就会自动生成。
低版本MongoDB兼容方案(4.2以下版本)
如果你的MongoDB版本低于4.2,不支持聚合管道更新,只能先查询对应工单的time_started,计算完成后再执行更新:
router.post('/completed', async function (req, res) { const time_completed = req.body.time_completed const workorder_id = req.body.workorder_id try { // 先查工单的开始时间 const order = await db.collection('workorders').findOne({ _id: ObjectId(workorder_id) }) const duration = new Date(time_completed) - new Date(order.time_started) // 执行更新 await db.collection('workorders').updateOne( { _id: ObjectId(workorder_id) }, { $set: { time_completed, duration } } ) res.send('Updated') } catch (err) { throw err } });
注意:该方案是非原子操作,高并发场景下可能出现数据不一致,建议优先升级MongoDB版本使用方案1或2。
内容的提问来源于stack exchange,提问作者Ujay Sidhpura
相关产品推荐
相关产品推荐

