bulkWrite 是什么
bulkWrite 把一批混合操作(插入、更新、替换、删除)放在一个请求里提交,驱动按数组顺序发往服务端,省掉逐条往返的延迟。它有两种执行模式:ordered 为默认值 true,遇到第一个失败就停止后续操作;设为 false 则继续执行剩余操作,最后集中返回失败清单。批量导入、批量修复这类场景应优先考虑它。
基本信息
| 操作类型 | insertOne / updateOne / updateMany / replaceOne / deleteOne / deleteMany |
|---|---|
| 执行模式 | ordered 默认 true;false 表示失败继续并集中汇报 |
| 返回内容 | insertedCount / matchedCount / modifiedCount / deletedCount / upsertedCount / upsertedIds |
| 常用选项 | ordered、bypassDocumentValidation、writeConcern、session(事务内) |
| 适用版本 | MongoDB 3.2 起支持;mongosh 与各语言驱动语法略有差异 |
典型使用场景
- 数据初始化与迁移:一次提交数千条插入,显著减少往返开销
- 订单批处理:同一批里既有状态更新也有过期记录删除,一条请求完成
- 对账修复:按主键 upsert 一批记录,重复执行结果一致
- 配合会话在副本集事务中批量写入,控制单次事务的操作规模
- 压测与造数:快速写入大量混合操作验证索引与写入能力
语法与失败处理
语法与失败处理
// 混合操作:插入、递增更新、删除放在同一次提交里
db.orders.bulkWrite([
{ insertOne: { document: { _id: 2001, sku: "B-1", qty: 1 } } },
{ updateOne: { filter: { _id: 1001 }, update: { $inc: { qty: 1 } } } },
{ updateMany: { filter: { status: "expired" }, update: { $set: { archived: true } } } },
{ replaceOne: { filter: { _id: 1002 }, replacement: { sku: "C-9", qty: 5 }, upsert: true } },
{ deleteOne: { filter: { _id: 999 } } }
], { ordered: false, writeConcern: { w: "majority" } }) // 顺序无关时用 false 提升吞吐
// ordered:false 下必须逐项检查失败,冲突项会出现在 writeErrors 里
try {
db.orders.bulkWrite(ops, { ordered: false })
} catch (e) {
if (e.writeErrors) { printjson(e.writeErrors.map(function (w) { return { i: w.index, msg: w.errmsg } })) }
else { throw e }
}返回字段读法
| 字段 | 含义 | 排查用途 |
|---|---|---|
| insertedCount | 成功插入的条数 | 与预期条数不符说明有插入失败,需查 writeErrors |
| matchedCount | 按条件命中的文档数 | 命中为 0 时检查过滤条件与字段类型是否匹配 |
| modifiedCount | 实际发生修改的文档数 | 小于 matchedCount 是常见现象,值相同则不计入修改 |
| deletedCount | 删除的文档数 | 与预期不符时先确认过滤条件 |
| upsertedCount / upsertedIds | 新增文档数量与新文档主键 | 未传 upsert:true 时不会出现该字段 |
| writeErrors | 失败项数组,含 index 与 errmsg | ordered:false 下必须逐项读取,否则失败被静默吞掉 |
超大批次要自行分批:单次提交的操作条数与整个请求的 16MB BSON 体积都有上限(具体数字以所用驱动文档为准),且大事务会长时间持有锁与缓存压力,导入通常按每批几千条提交。
ordered:false 的批量写不是全有或全无:部分成功部分失败是常态,业务侧要能接受中间状态,并让失败项可重放且幂等。