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

使用bulkWrite+updateOne设upsert=true仍创建新文档的问题

解决MongoDB bulkWrite upsert重复创建文档的问题

场景还原

从Google Calendar API获取节假日数据后,执行以下批量更新/插入代码,但开启upsert=true后仍会重复创建文档:

Holiday.bulkWrite(
    holidays.map((holiday) => ({
        updateOne: {
            filter: { holidayId: holiday.id },
            update: { $set: holiday },
            upsert: true,
        },
    }))
)

问题原因及解决办法

1. 统一holiday.id的格式一致性

如果每次获取的holiday.id存在大小写差异、前后空格或数据类型不匹配,会导致MongoDB无法匹配到已有文档,触发upsert创建新记录。
解决: 标准化处理holiday.id格式,同步更新数据库字段:

Holiday.bulkWrite(
    holidays.map((holiday) => {
        const standardizedId = holiday.id.trim().toLowerCase();
        return {
            updateOne: {
                filter: { holidayId: standardizedId },
                update: { $set: { ...holiday, holidayId: standardizedId } },
                upsert: true,
            },
        };
    })
)

2. 给holidayId添加唯一索引

仅靠代码逻辑的过滤无法强制字段唯一性,必须给holidayId建立唯一索引,让MongoDB从底层保证该字段不重复。
解决:

  • 在Mongoose模型中配置:
    const holidaySchema = new mongoose.Schema({
        holidayId: { type: String, unique: true, required: true },
        // 其他字段定义...
    });
    
  • 或直接在MongoDB Shell中执行:
    db.holidays.createIndex({ holidayId: 1 }, { unique: true })
    
    建立索引后,若出现重复的holidayId,MongoDB会抛出重复键错误,避免重复创建文档。

3. 排除_id字段(若存在)

如果从Google Calendar API返回的holiday对象中包含_id字段,upsert时会因为_id不匹配而创建新文档(MongoDB默认以_id作为主键)。
解决: 移除_id字段后再执行更新:

Holiday.bulkWrite(
    holidays.map((holiday) => {
        const { _id, ...cleanHoliday } = holiday;
        return {
            updateOne: {
                filter: { holidayId: holiday.id },
                update: { $set: cleanHoliday },
                upsert: true,
            },
        };
    })
)

内容的提问来源于stack exchange,提问作者BKM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 01:36:01