如何在Mongoose使用updateOne时获取新增推送的子文档_id?
解决MongoDB数组推送后获取子文档_id的并发安全方案
问题根源
你当前的方案存在并发风险:updateOne 和 findById 是两个独立的数据库操作,高并发场景下,其他请求可能在这两个操作之间向数组中插入新元素,导致你拿到的不是自己刚推送的子文档_id。
方案一:预生成_id(推荐)
MongoDB的ObjectId支持在客户端生成,你可以先创建好子文档的_id,再执行推送操作,之后直接使用预生成的_id即可,完全避免并发问题。
代码示例(基于Mongoose):
const mongoose = require('mongoose'); // 预生成ObjectId const newSubDocId = new mongoose.Types.ObjectId(); await model.updateOne( { _id: docId }, { $push: { arr: { _id: newSubDocId, a: 3, b: 4 } } } ); // 直接使用预生成的_id,无需查询 console.log(newSubDocId);
方案二:使用findOneAndUpdate原子操作
findOneAndUpdate是原子性的更新+查询操作,设置返回更新后的文档,这样能确保拿到的是自己这次更新后的数组最后一项,不会被其他并发请求干扰。
代码示例(基于Mongoose):
const updatedDoc = await model.findOneAndUpdate( { _id: docId }, { $push: { arr: { a: 3, b: 4 } } }, { new: true } // 指定返回更新后的文档 ); const newSubDocId = updatedDoc.arr[updatedDoc.arr.length - 1]._id; console.log(newSubDocId);
注意事项
- 如果使用原生MongoDB驱动,对应的参数是
returnNewDocument: true,而非Mongoose的new: true。 - 方案一性能更优,减少了一次数据库查询操作,且彻底规避并发问题,优先推荐。
内容的提问来源于stack exchange,提问作者Navid Naseri
相关产品推荐
相关产品推荐

