You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Mongoose findByIdAndUpdate+upsert时未生成_id的问题咨询

问题解答:Mongoose findByIdAndUpdate + upsert 插入时未生成_id

这不是正常行为,Mongoose 默认会自动为新插入的文档生成 _id(ObjectId 类型),出现该问题的核心原因是你的代码逻辑或 Schema 配置存在冲突,以下是具体分析和解决方案:

核心原因分析

  1. 查询条件中的_id值异常
    你在查询条件中指定了 {_id: id},当执行 upsert 插入新文档时,MongoDB 会直接将传入的 id 值作为新文档的 _id。如果 id 是 undefined、null 或非合法的 ObjectId 格式,会导致 _id 字段不符合预期(比如存入字符串类型的无效值,甚至出现字段缺失的情况)。

  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:43:35