Skip to content

Atomicity & Transactions

Single-document Atomic Operations

Update operators that increment, push and set in one round trip, without a transaction.

IntermediateAbout 4 minutes

Atomicity is wasted if you read, change in Node, write. Two checkouts both read stock: 1, both write 0. $inc (and $push, $set, $bit) run on the server in one document lock. The CRUD module listed the operators; this lesson is why they are the concurrency primitive.

db.products.updateOne(
  { name: "Mechanical Keyboard", stock: { $gte: 1 } },
  { $inc: { stock: -1 }, $set: { updatedAt: new Date() } }
)
// matchedCount: 0 → sold out. No separate read.
Do not go negative — filter and $inc in one write
db.products.findOneAndUpdate(
  { name: "Mechanical Keyboard", stock: { $gte: 1 } },
  { $inc: { stock: -1 } },
  { returnDocument: "after" }
)
Return the new document in the same round trip

Several operators in one updateOne are still one atomic write: $inc stock and $set a timestamp. findOneAndUpdate / findOneAndDelete are the same guarantee plus a returned document. Conditional stock is a filter, not a transaction. Two collections (order + stock) still need the next lesson or a product decision to accept a mismatch. Races that are not solved by $inc — last-write-wins on city — are the Concurrency module.

Interview question

How do you decrement stock without a race or a negative count?

Think about it first.