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

MongoDB bulkWrite插入随机生成_id仍报E11000重复键错误

问题产生原因

报错核心是代码逻辑存在三个明显缺陷,和集合初始为空、新生成随机ID重复无关:

  • bulkWrite调用逻辑完全错误:循环内只要destinations数组不为空就触发批量写入,但写入完成后从未清空数组。第一次循环数组存入1条文档并执行写入,第二次循环会往数组里追加第二条文档,此时数组共2条记录(包含第一次已经写入过的文档),再次触发bulkWrite就会重复提交已存在的文档,直接触发_id唯一键冲突。
  • 异步操作未加等待:bulkWrite是异步方法,原代码没有加await关键字,调用后不会等待写入完成就进入下一轮循环,会导致写入时序和数组状态混乱,进一步放大重复提交问题。
  • 自定义随机ID生成方案不可靠:Math.random()是伪随机数,乘以10000000000000取整的生成方式本身就存在碰撞概率,不是合法的唯一ID生成方案。
修复方案

按以下三点调整代码即可解决问题:

  • 调整批量写入逻辑:不要每轮循环都触发写入,选择循环结束后统一写入,或者按固定批次(如每500条)写入,每次写入完成后必须清空待操作数组。
  • 所有异步数据库操作前加await,保证时序正确。
  • 废弃自定义随机ID生成逻辑,改用MongoDB官方提供的ObjectId生成唯一主键,从根源避免ID碰撞。

修复后的完整代码如下:

import listingDestinations from '/common/info/listingDestinations';
import { ObjectId } from 'mongodb'; // Meteor环境可替换为从meteor/mongo引入ObjectId

Migrations.add({
    version: 329,
    name: 'Add ListingDestinations',
    async up() {
        const {default: ListingDestination} = require('/common/db/listingDestination');
        let destinations = [];
        for (const listingDestination of listingDestinations) {
            const _id = new ObjectId();
            destinations.push({
                insertOne: {
                    document: {
                        _id,
                        ...listingDestination,
                    },
                },
            });
            // 分批写入,避免单次批量操作数据量过大
            if (destinations.length >= 500) {
                await ListingDestination.rawCollection().bulkWrite(destinations);
                destinations = [];
            }
        }
        // 写入最后一批不足500条的剩余数据
        if (destinations.length > 0) {
            await ListingDestination.rawCollection().bulkWrite(destinations);
        }
    },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 01:30:27