I have some documents with below format
{
"count_used" : Int64,
"last_used" : Date,
"enabled" : Boolean,
"data" : String
}
I use the last_used
field to sort on within an aggregate
query so the last used document is served first. I use updateOne
after the aggregate to bump the last used field using the below query. So every read request will change the last_used field date stamp.
updateOne(
{ _id: result['_id']},
{
$currentDate: { 'last_used': true },
$inc: { 'count_used': 1 }
}
)
The problem i have is clients will make 5 concurrent requests and instead of receiving document 1,2,3,4,5 they will get 1,1,1,2,2 for example.
I'm guessing this is because there is no lock between the read and the update, so several reads get same results before the update is performed.
Is there any way around this?
Update with below aggregate nodejs code
db.collection('testing').aggregate([{
$project: {
last_used : 1,
count_used : 1,
doc_type : 1,
_id : 1,
data : 1,
is_type : { $setIsSubset: [ [type], '$doc_type' ] }
}
},
{ $match: {
$or: query}
},
{ $sort: {
is_type: -1,
last_used: 1
}
},
{
$limit: 1
} ]).next(function (error, result) {
db.collection('adverts').updateOne({_id: result['_id']}, {$currentDate: {'last_used': true}, $inc: {'count_used': 1}})
}
The problem is that multiple read requests come in from same client who issues multiple concurrent requests, which means they hit db at the same time and read the same data before the updateOne
fires.