Patterns · 4 of 4
Upsert & soft-delete
Two idempotent patterns you'll reach for again and again.
Upsert by key
proc upsert_user(email, name) {
let existing = find_one("users", {email: email})
if existing == null {
insert("users", {email: email, name: name, signups: 1})
return {created: true, email: email}
}
update("users", {email: email}, {
$set: {name: name},
$inc: {signups: 1}
})
return {created: false, signups: existing.signups + 1}
}
Upsert with merge
proc upsert_setting(user_id, key, value) {
let s = find_one("settings", {user_id: user_id})
if s == null {
insert("settings", {user_id: user_id, prefs: {key: value}})
} else {
update("settings", {user_id: user_id}, {$set: {"prefs.key": value}})
}
return {ok: true}
}
Counter upsert
proc bump_counter(name) {
let c = find_one("counters", {name: name})
if c == null {
insert("counters", {name: name, value: 1})
return {value: 1}
}
update("counters", {name: name}, {$inc: {value: 1}})
return {value: c.value + 1}
}
Soft-delete
proc soft_delete(collection, id, actor) {
let doc = find_one(collection, {_id: id})
if doc == null { abort "not found" }
update(collection, {_id: id}, {
$set: {deleted: true, deleted_at: "now", deleted_by: actor}
})
insert("audit_log", {
action: "delete", collection: collection,
doc_id: id, actor: actor, original: doc
})
return {ok: true}
}
Soft-undelete
proc undelete(collection, id, actor) {
update(collection, {_id: id, deleted: true}, {
$unset: {deleted: "", deleted_at: "", deleted_by: ""}
})
insert("audit_log", {action: "undelete", doc_id: id, actor: actor})
return {ok: true}
}
Filter out soft-deletes in reads
proc list_active_posts() {
return find("posts", {deleted: {$exists: false}})
}
Or just {deleted: {$ne: true}} if you sometimes set deleted: false.
Hard-purge after grace period
proc purge_old_soft_deletes(days) {
let candidates = find("posts", {deleted: true, deleted_age_days: {$gte: days}})
for p in candidates {
delete_one("posts", {_id: p._id})
insert("audit_log", {action: "purge", doc_id: p._id})
}
return {purged: count("posts", {deleted: true})}
}
Idempotent insert with dedupe key
proc record_payment(idempotency_key, account_id, amount) {
if count("payments", {idempotency_key: idempotency_key}) > 0 {
return {duplicate: true}
}
insert("payments", {
idempotency_key: idempotency_key,
account_id: account_id, amount: amount, status: "ok"
})
update("accounts", {_id: account_id}, {$inc: {balance: amount}})
return {duplicate: false}
}