MongoDB执行findOne未查询到对应文档时如何自动新增新文档?
问题解答
首先明确MongoDB的findOne方法行为:未匹配到符合条件的文档时,会直接返回null,你当前的代码没有对空返回做判断,当查询不到用户时访问data.u_id会直接抛出类型错误。
优化实现方案(查询不到自动新建用户)
推荐直接使用findOneAndUpdate方法配合upsert参数,一步完成「查询+不存在就插入」的原子操作,避免并发场景下的重复插入问题,代码如下:
async function getUserData(_key) { const client = new MongoClient(mongoUri, { useNewUrlParser: true, useUnifiedTopology: true }); try { await client.connect(); const collection = client.db("myDb").collection("myCollection"); const query = { t_id: String(_key[0]), c_id: String(_key[1]), u_id: String(_key[2]) }; // upsert设为true表示查询不到时自动插入新文档 // returnDocument设为after表示返回插入/更新后的文档内容 const { value: data } = await collection.findOneAndUpdate( query, { $setOnInsert: query }, // 仅插入时写入query里的三个字段,有其他默认字段可自行追加 { upsert: true, returnDocument: 'after' } ); const returnData = { u_id: data.u_id, t_id: data.t_id, c_id: data.c_id }; return returnData; } finally { await client.close(); } }
保留原有findOne写法的兼容方案
如果不想修改原有查询逻辑,也可以手动做空值判断后执行插入:
const data = await collection.findOne(query); // 未查询到数据时执行插入 if (!data) { await collection.insertOne(query); // 插入后直接用query的内容构造返回,无需二次查询 return { u_id: query.u_id, t_id: query.t_id, c_id: query.c_id }; } // 原有返回逻辑 return { u_id: data.u_id, t_id: data.t_id, c_id: data.c_id };
注意事项
优先选择findOneAndUpdate的原子操作方案,避免多个请求同时查询同一个不存在的用户时,同时触发插入操作导致重复数据。$setOnInsert的作用是只有在执行插入操作的时候才会更新对应的字段,后续重复查询到该用户时不会修改原有文档内容,完全匹配你的业务需求。
内容的提问来源于stack exchange,提问作者Callum Fowler
相关产品推荐
相关产品推荐

