I'm using NodeJS with Express to create a simple rest api. My workflow:
- I pass an object via POST URI
- I want to save that to the DB. If it is in the DB, I want to increment a count of how many times we've tried to save the object
My code for saving is as such:
await collection.updateOne({
// match all the properties
}, {
$inc: {
'encountered': 1
}
}, {
upsert: true,
});
This, however, creates a race condition if I make a number of concurrent calls at once... For example, if I make the POST request 5 times at the same time, I may get two results:
one time, encountered: 3x second time, encountered: 2x
I assume that the first insert searched the DB, didn't find the item, and was prepared for insert, while the second insert got thread time, found no item, and also prepared for insert. Then, the first insert fired, incremented several times, and then second insert fired, and incremented several times.
How do I deal with this? A global variable trying to mimic singleton..? I'm still not sure that'd be thread-safe though... I don't mind worse performance, but I need DB writes to be absolutely thread-safe/atomic, i.e. search and update to be considered an atomic operation.
Edit: Alternatively, I'd be happy not to accept any POST call (i.e. block the POST operation) until my previous call was fully resolved..? I'm not sure what's the proper NodeJS way to solve this.
Edit2: I also tried db.collection.createIndex
, which then fails the writes. I am afraid that upon re-trying this failed write, I'd run into the same problem.