Measured while implementing #13854 (SqlDriver.bulkUpdate transaction wrapper). #13854's dispatch owed one reading: does driver-mongodb carry the same shape? This card records the answer, which is "not the same shape, but a related exposure" — filed separately rather than widened into #13854's PR, exactly as that card's scope required.
The reading (measured on origin/main, by symbol)
packages/drivers/driver-mongodb/src/mongodb-driver.ts:
So the per-row autocommit loop #13854 repaired does not exist here. That half of the reading is settled.
Why this is still worth a card
The consequence class may nevertheless be reachable, through a different mechanism. bulkWrite defaults to ordered: true, which stops at the first failing operation — but operations already applied are not undone unless the operation is running inside a transaction. When the caller passes no options.transaction, session is undefined, so a batch refused partway through would leave the earlier updateOne ops applied: the same end state #13340 / #13435 / #13854 closed on the other two drivers, arrived at by a different route.
⚠️Split by evidence, because the two halves are not equally established:
Why the #13854 fix does not simply transfer
⛔ Do not assume the repair is "wrap it in a transaction like the SQL driver". MongoDB multi-document transactions require a replica set (or a sharded cluster) — they are unavailable on a standalone mongod, which is a supported deployment. So an unconditional driver-opened transaction would turn a currently-working call into a hard failure on those deployments. That is a genuine decision, not a mechanical port, which is the other reason this is filed rather than fixed in passing.
Sketch of the option space, for whoever picks this up:
- Open a transaction only when the topology supports one, and document the weaker guarantee elsewhere — declared ≠ enforced, which is the shape this project usually refuses.
- Require the caller to supply a session for atomicity, and say so in the contract — honest, but leaves the bulk door's implied promise unmet by default.
- Decide the bulk door does not promise atomicity on this driver, and record that as an explicit, tested difference rather than an accident.
Related
#13854 (driver-sql, the card this reading was owed to) · #13435 · #13340 (the driver-memory half of the same defect class)
Filed unassigned and unlabelled for triage, per the dispatch's out-of-scope rules.
Generated by Claude Code
Measured while implementing #13854 (
SqlDriver.bulkUpdatetransaction wrapper). #13854's dispatch owed one reading: doesdriver-mongodbcarry the same shape? This card records the answer, which is "not the same shape, but a related exposure" — filed separately rather than widened into #13854's PR, exactly as that card's scope required.The reading (measured on
origin/main, by symbol)packages/drivers/driver-mongodb/src/mongodb-driver.ts:bulkUpdate(:505) is NOTdriver-sql's shape. It does not loop over N awaitedupdate()calls. It mapsupdatesinto abulkOpsarray ofupdateOnedescriptors and issues onecollection.bulkWrite(bulkOps, { session }), then re-reads the affected ids.bulkDelete(:534) is onecollection.deleteMany({ id: { $in: ids } }, { session })— the same "single statement" shape asSqlDriver.bulkDelete, which driver-sql:bulkUpdateis a sequential per-row loop with no transaction — a mid-batch refusal leaves earlier rows committed (driver-turso inherits it viasuper.) #13854 measured and correctly left out of scope.sessionin both comes fromgetSession(options)(:687), which is exactlyoptions.transaction as ClientSession | undefined— the sameoptions.transactionparameterisation the SQL driver uses.So the per-row autocommit loop #13854 repaired does not exist here. That half of the reading is settled.
Why this is still worth a card
The consequence class may nevertheless be reachable, through a different mechanism.
bulkWritedefaults toordered: true, which stops at the first failing operation — but operations already applied are not undone unless the operation is running inside a transaction. When the caller passes nooptions.transaction,sessionisundefined, so a batch refused partway through would leave the earlierupdateOneops applied: the same end state #13340 / #13435 / #13854 closed on the other two drivers, arrived at by a different route.sessionplumbing described above.bulkWritesemantics rather than something observed against this driver, and it was deliberately not driven to a repro — driver-sql:bulkUpdateis a sequential per-row loop with no transaction — a mid-batch refusal leaves earlier rows committed (driver-turso inherits it viasuper.) #13854's scope was explicit thatdriver-mongodbis read-only, measure and report. It needs a real refusal driven through this door before anyone acts on it.Why the #13854 fix does not simply transfer
⛔ Do not assume the repair is "wrap it in a transaction like the SQL driver". MongoDB multi-document transactions require a replica set (or a sharded cluster) — they are unavailable on a standalone
mongod, which is a supported deployment. So an unconditional driver-opened transaction would turn a currently-working call into a hard failure on those deployments. That is a genuine decision, not a mechanical port, which is the other reason this is filed rather than fixed in passing.Sketch of the option space, for whoever picks this up:
Related
#13854 (
driver-sql, the card this reading was owed to) · #13435 · #13340 (thedriver-memoryhalf of the same defect class)Filed unassigned and unlabelled for triage, per the dispatch's out-of-scope rules.
Generated by Claude Code