Mongoose中如何使用findByIdAndUpdate累加数据而非全量覆盖
问题场景
当前定义的Message Mongoose模型Schema如下:
var Message = mongoose.model('Message', { name: String, message: String, votes: Number })
现有投票更新接口代码:
app.put('/messages/:id', (req, res) => { Message.findByIdAndUpdate({_id: req.params.id}, {votes: req.body.votes}).then(function(message){ res.send(message) }) })
现有逻辑会直接用请求传入的votes值覆盖库中原有值:比如原有投票数为1、请求传入值为5时,最终votes会被更新为5,无法实现「在原有投票数基础上累加传入值、最终得到6票」的需求。
解决方案
使用MongoDB原生的$inc原子更新操作符即可实现数值累加,该操作在数据库层面原子执行,不需要先查询文档手动计算,并发场景下也不会出现计数不准的问题。
修改后的代码如下:
app.put('/messages/:id', (req, res) => { Message.findByIdAndUpdate( req.params.id, // findByIdAndUpdate第一个参数直接传id字符串即可,无需额外包装查询对象 { $inc: { votes: req.body.votes } }, // $inc用于数字字段增减,传正数累加、传负数扣减 { new: true } // 加该配置会返回更新后的最新文档,默认配置返回的是更新前的旧文档 ).then(function(message){ res.send(message) }) })
注意事项
- 不要使用「先查询文档拿到旧votes值→手动相加计算新值→再save保存」的写法,并发请求下会出现计数覆盖、结果丢失的问题,
$inc原子更新可以完全规避这个坑。 - 如果后续需要实现取消投票、扣减票数的逻辑,直接给
$inc传入对应的负数值即可,不需要调整更新逻辑。
内容的提问来源于stack exchange,提问作者albert
相关产品推荐
相关产品推荐

