一聚教程网:一个值得你收藏的教程网站

热门教程

MongoDB如何批量插入数据并避免重复写入?

时间:2026-08-06 07:46:48 编辑:袖梨 来源:一聚教程网

insertMany 默认 ordered: true 会因重复键中断插入,需设 { ordered: false } 并检查 writeErrors;唯一索引是防重复的唯一原子手段,建索引须 { unique: true } 且先清理重复数据;bulkWrite 更适合混合操作,避免滥用 upsert;批次大小应按 BSON 体积(≤16MB)而非条数控制,注意 _id 类型一致性。

insertMany 默认会因重复键中断,必须显式关掉 ordered

默认 ordered: true 意味着只要某条文档触发唯一索引冲突(比如 E11000 duplicate key),后续所有文档立刻停止插入。这不是性能问题,而是行为设定——你看到“只插了一半”,其实是被主动截断了。

  1. 必须传 { ordered: false } 才能让其余文档继续执行
  2. 错误不会抛出异常,而是收在返回值的 writeErrors 字段里,得手动检查
  3. 别用 try/catch 包整个 insertMany 来判断成败:即使有 99 条失败,result.ok 还是 1

唯一索引不是可选项,是防止重复的唯一原子手段

靠应用层“先查再插”或 upsert 都扛不住并发竞态,两个请求同时没查到,就都插进去了。只有存储引擎层的唯一索引能真正拦住。

  1. 建索引命令必须带 { unique: true },例如:db.users.createIndex({ email: 1 }, { unique: true })
  2. 已有重复数据时,建索引会直接失败,得先清理:db.users.aggregate([ { $group: { _id: "$email", count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ])
  3. 字段值含空格、大小写不一致、null 多次插入,都会让索引失效;需要配 collation 或改用 sparse: true

bulkWrite 比 insertMany 更适合混合场景,但别用 upsert 替代 insert

如果你既要插新文档,又要更新部分字段,bulkWrite 是更清晰的选择;但千万别为了“跳过重复”而滥用 upsert: true

  1. upsert 本质是“查 + 插/改”,每次多一次索引查找,性能比纯 insertOne
  2. 漏写 $set 或 filter 错误,可能把整条文档覆盖成空对象
  3. 真要跳过重复,就用 bulkWrite + insertOne + { ordered: false },语义干净、开销最小
  4. 失败定位靠 result.writeErrors[i].index,对应原始数组下标,不是插入后顺序

批次大小不是按条数卡死,得按 BSON 总体积算

insertMany 提交的是一个 BSON 数组,总大小不能超 16MB。单条文档 1KB,1.5 万条就满了;如果文档长短不一,硬按 10 万条切批,大概率踩中 Document too large for insert

  1. 预估体积用:Buffer.byteLength(JSON.stringify(doc), 'utf8'),再加 20% 余量
  2. Node.js 里别一次性 JSON.parse(fs.readFileSync(...)) 加载全部数据,用 stream.Transform 边读边 chunk
  3. 驱动会自动按 maxWriteBatchSize(10 万)拆批,但这是上限不是建议值;生产环境推荐 ≤5 万条/批
实际写入逻辑里最易被忽略的,是 _id 类型一致性——字符串 "507f1f77bcf86cd799439011"ObjectId("507f1f77bcf86cd799439011") 在索引眼里是两个值,看着重复,其实全都能插进去。

热门栏目