最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
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),后续所有文档立刻停止插入。这不是性能问题,而是行为设定——你看到“只插了一半”,其实是被主动截断了。
- 必须传
{ ordered: false }才能让其余文档继续执行 - 错误不会抛出异常,而是收在返回值的
writeErrors字段里,得手动检查 - 别用
try/catch包整个insertMany来判断成败:即使有 99 条失败,result.ok还是1
唯一索引不是可选项,是防止重复的唯一原子手段
靠应用层“先查再插”或 upsert 都扛不住并发竞态,两个请求同时没查到,就都插进去了。只有存储引擎层的唯一索引能真正拦住。
- 建索引命令必须带
{ unique: true },例如:db.users.createIndex({ email: 1 }, { unique: true }) - 已有重复数据时,建索引会直接失败,得先清理:
db.users.aggregate([ { $group: { _id: "$email", count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]) - 字段值含空格、大小写不一致、
null多次插入,都会让索引失效;需要配collation或改用sparse: true
bulkWrite 比 insertMany 更适合混合场景,但别用 upsert 替代 insert
如果你既要插新文档,又要更新部分字段,bulkWrite 是更清晰的选择;但千万别为了“跳过重复”而滥用 upsert: true。
-
upsert本质是“查 + 插/改”,每次多一次索引查找,性能比纯insertOne差 - 漏写
$set或 filter 错误,可能把整条文档覆盖成空对象 - 真要跳过重复,就用
bulkWrite+insertOne+{ ordered: false },语义干净、开销最小 - 失败定位靠
result.writeErrors[i].index,对应原始数组下标,不是插入后顺序
批次大小不是按条数卡死,得按 BSON 总体积算
insertMany 提交的是一个 BSON 数组,总大小不能超 16MB。单条文档 1KB,1.5 万条就满了;如果文档长短不一,硬按 10 万条切批,大概率踩中 Document too large for insert。
- 预估体积用:
Buffer.byteLength(JSON.stringify(doc), 'utf8'),再加 20% 余量 - Node.js 里别一次性
JSON.parse(fs.readFileSync(...))加载全部数据,用stream.Transform边读边 chunk - 驱动会自动按
maxWriteBatchSize(10 万)拆批,但这是上限不是建议值;生产环境推荐 ≤5 万条/批
_id 类型一致性——字符串 "507f1f77bcf86cd799439011" 和 ObjectId("507f1f77bcf86cd799439011") 在索引眼里是两个值,看着重复,其实全都能插进去。