This code looks safe but contains a race:
const existing = await collection.findOne({ userId, day });
if (!existing) {
await collection.insertOne({ userId, day, count: 1 });
}
Two Lambda invocations can both observe no document and both insert. Application checks improve error messages; they do not enforce invariants under concurrency.
Let an index enforce uniqueness#
await collection.createIndex({ userId: 1, day: 1 }, { unique: true });
Now the database is the final authority. The application should handle duplicate-key errors according to the operation: return the existing resource, report a conflict, or treat the retry as a no-op.
Use atomic upserts#
For create-if-absent behavior:
await collection.updateOne(
{ userId, day },
{
$setOnInsert: {
userId,
day,
createdAt: new Date(),
},
$inc: { count: 1 },
},
{ upsert: true },
);
One database operation avoids the gap between read and write. Confirm that the filter is supported by the unique index; otherwise concurrent upserts can still surprise you.
Put state conditions in the write#
Conditional updates safely claim work:
const job = await jobs.findOneAndUpdate(
{ _id: jobId, status: "pending" },
{ $set: { status: "processing", claimedAt: new Date() } },
{ returnDocument: "after" },
);
Only one worker changes pending to processing. A missing result means another worker won or the state is no longer eligible.
Multi-document transactions are useful when several documents must change together, but they add latency and operational constraints. Prefer one-document atomic designs when the domain allows them.
Test writes concurrently, not only one after another. Safe MongoDB code expresses the invariant in an index or atomic filter, close to the place that arbitrates competing writes.