事务内单次 insertMany 最多写入 1000 个文档,超限报 TransactionTooLarge 错误;该限制独立于 transactionSizeLimitMB,需应用层主动分批,推荐每批 500 条并设置 maxTimeMS 防超时。

事务内单次 insertMany 最多写入 1000 个文档
MongoDB 默认对单个事务内的写入文档数做了硬性限制:insertMany() 在事务中最多接受 1000 个文档。超过这个数量会直接报错 TransactionTooLarge,而不是静默截断或分批执行。
这个限制与 transactionSizeLimitMB 参数无关——后者控制的是事务总 BSON 大小(默认 16MB),但文档计数限制是独立存在的。即使你传入 500 个超大文档(接近 16MB),再加第 501 个也会失败。
- 必须在应用层主动切分:比如把 5000 条 JSON 解析后拆成 5 批,每批 ≤1000 条
- 不要依赖驱动自动分片;PyMongo、Node.js 驱动的
insertMany()都不会帮你拆 - 若用
bulkWrite(),同样受此约束:每个insertOne或insertMany操作都算作“一次写入”,但整批bulkWrite()中所有操作共享同一个事务上下文,所以总数仍不能超 1000
为什么不能靠 increase transactionSizeLimitMB 来绕过文档数限制
transactionSizeLimitMB 只放宽 BSON 总体积上限,不影响文档计数逻辑。MongoDB 内核在事务预检阶段就校验文档数量,不读取实际 payload 大小。
你改了这个参数,能多塞几个大文档,但依然卡死在 1000 这个整数阈值上。实测:设为 100 MB 后尝试插入 1001 条空对象 {},照样报 TransactionTooLarge。
- 该参数需重启 mongod 生效,且只影响单个事务的内存和 oplog 占用,不改变原子性保障粒度
- 生产环境不建议调高;超过默认值会显著增加 WiredTiger 缓存压力,容易触发
WriteConflict - 真正需要大量写入时,应优先考虑是否真需要事务——很多场景用带重试的幂等
updateMany()更轻量
用 bulkWrite + ordered: false 绕不过去
有人试图用 bulkWrite([{ insertOne: ... }, { insertOne: ... }], { ordered: false }) 塞几千条,以为“乱序执行”就能规避计数检查。不行。
事务机制不管你是 ordered: true 还是 false,只要所有操作都在同一个 session.withTransaction() 回调里,MongoDB 就把它们当做一个原子单元统计总文档数。
-
ordered: false只影响错误传播(某条失败不影响后续),不解除事务级文档上限 - 即便每条
insertOne看似独立,它们仍共用同一事务 ID,服务端聚合计数时全算进去 - 错误信息明确指向数量而非顺序:
"number of documents in transaction exceeds limit of 1000"
最稳妥的分批策略:500 条/批 + maxTimeMS 守护
别卡着 1000 顶格写。留余量才能扛住网络抖动、锁竞争或慢查询拖慢单批耗时。
推荐固定每批 500 条,并显式设置 maxTimeMS:
await session.withTransaction(async () => {
await collection.insertMany(docs.slice(i, i + 500), {
maxTimeMS: 5000 // 确保单批绝不超 5 秒
});
});
- 500 是经验值:兼顾吞吐与容错,避免单批因某条脏数据阻塞整个事务
-
maxTimeMS必须设在insertMany()选项里,不是 session.startTransaction() 里 - 事务总生命周期仍受
transactionLifetimeLimitSeconds约束(默认 60 秒),所以 10 批 × 5 秒 = 刚好压线,建议留出缓冲

















