Databases · 05/09 6 min1 hands-on
Updating safely
$set and $inc, getting the updated document back, and the race that oversells your stock.
Update operators
Product.updateOne({ _id: id }, { $set: { price: 25 } }); // set fields
Product.updateOne({ _id: id }, { $inc: { stock: -1 } }); // add or subtract
Post.updateOne({ _id: id }, { $push: { tags: "new" } }); // append to an array
updateOne resolves to a summary such as { matchedCount: 1, modifiedCount: 1 }, not the document.
Getting the document back
await Product.findByIdAndUpdate(id, { $inc: { stock: 5 } }); // returns the OLD document
await Product.findByIdAndUpdate(id, { $inc: { stock: 5 } }, { new: true }); // returns the NEW one
This one trips everyone at least once.
The overselling race
const p = await Product.findById(id); // A reads stock = 1 … B reads stock = 1
if (p.stock < qty) return false; // both pass the check
p.stock -= qty; await p.save(); // both save: you sold 2 lamps you didn't have
Between your read and your write, another request can sneak in. The fix: let the database do the check and the change in one step.
const r = await Product.updateOne(
{ _id: id, stock: { $gte: qty } }, // only matches if there's enough
{ $inc: { stock: -qty } },
);
return r.modifiedCount === 1; // 0 means someone else got there first
The exercise fires two buyers at the last lamp at the same moment. Watch the naive version fail, then fix it.
Your turn · 1 exercise0/1 solved
Update without losing stock
restock should return the updated product. buy must never sell more than is in stock, even when two orders arrive at once.
Loading editor…
Next in Databases
Relations and populate