使用Mongoose findByIdAndUpdate+upsert时未生成_id的问题咨询
问题解答:Mongoose findByIdAndUpdate + upsert 插入时未生成_id
这不是正常行为,Mongoose 默认会自动为新插入的文档生成 _id(ObjectId 类型),出现该问题的核心原因是你的代码逻辑或 Schema 配置存在冲突,以下是具体分析和解决方案:
核心原因分析
查询条件中的
_id值异常
你在查询条件中指定了{_id: id},当执行 upsert 插入新文档时,MongoDB 会直接将传入的id值作为新文档的_id。如果id是undefined、null或非合法的 ObjectId 格式,会导致_id字段不符合预期(比如存入字符串类型的无效值,甚至出现字段缺失的情况)。Schema 配置问题
如果你的集合 Schema 中手动设置了_id: false,或者自定义了_id字段的规则(比如指定为String类型且未开启自动生成),Mongoose 会停止自动生成_id,需要你手动提供合法的_id值。
解决方案
方案1:调整查询逻辑,让Mongoose自动生成_id
如果你的需求是「有对应_id的文档就更新,没有则创建新文档并自动生成_id」,那么不要在查询条件中指定_id,改用其他唯一标识字段作为查询条件(比如userId、email),使用findOneAndUpdate替代findByIdAndUpdate:
// 示例:用email作为唯一查询条件 const newDocument = await collection.findOneAndUpdate( { email: targetEmail }, newObj, { upsert: true, new: true } );
方案2:处理无效id的场景,手动区分更新/插入
如果必须以_id作为判断依据,可先检查id的有效性,无效时直接调用create方法生成新文档(自动生成_id):
let newDocument; try { // 尝试查找并更新已有文档 newDocument = await collection.findByIdAndUpdate(id, newObj, { new: true }); // 如果未找到文档,手动创建 if (!newDocument) { newDocument = await collection.create(newObj); } } catch (err) { // 捕获无效ObjectId的错误,直接创建新文档 if (err.name === 'CastError') { newDocument = await collection.create(newObj); } else { throw err; } }
方案3:检查并修正Schema配置
确保你的集合Schema未禁用自动生成_id的逻辑,默认配置如下(无需手动添加):
const mongoose = require('mongoose'); const schema = new mongoose.Schema({ // 其他字段... // Mongoose会自动添加 _id: { type: mongoose.ObjectId, auto: true } });
如果手动配置了_id字段,确保开启自动生成或提供合法值:
// 正确示例:自定义类型但开启自动生成(比如用UUID) const { v4: uuidv4 } = require('uuid'); const schema = new mongoose.Schema({ _id: { type: String, default: uuidv4 }, // ...其他字段 });
内容的提问来源于stack exchange,提问作者Ahmed Khairy
相关产品推荐
相关产品推荐

