Reputation: 8237
Given the schema:
{
widgets: [{
widget: {type: mongoose.Schema.Types.ObjectId, ref: 'widget'},
count: {type: Number}
}]
}
and an application route where:
In this setup, if I have 2 parallel requests to perform the same action, both checks in number 2 pass and the document is saved with 2 copies of the widget, even though that's "illegal" in my business logic.
The async flow looks like:
I thought that document versioning (__v
) would solve this for me as it has in the past, but apparently I never understood this to begin with because both requests are running sequentially and my debugger shows that the version of the document is X in both pre-save states, and X+1 in the post-save state. I don't understand why that doesn't throw a version error.
I think that this is an asynchronous problem to solve, not necessarily strictly Mongoose, and have tagged as such.
Edit: This works but seems remarkably verbose:
model
.findOneAndUpdate({
_id: doc._id,
__v: doc.__v
},
{
$push: {
widgets: {
widget: widget_id,
qty: 1
}
},
$inc: {
__v: 1
}
},
function(err, doc) {
// ...
});
Also, it is unfortunate that I can't alter my existing doc and then run the save()
method on it.
My searching found this bug where the versionKey
didn't increment automatically when using this method. I suppose I really don't understand versionKey
properly!
Upvotes: 0
Views: 1014
Reputation: 693
Then maybe you can try to add widgets check in update query:
model.findById(doc._id, function(err, doc) {
// handle error
// on update query check if there is no such widget in widgets array
doc.update(
{ _id: doc._id, { 'widgets.widget': { $nin: [widget_id] } }},
{
$push: {
widgets: { widget: widget_id, count: widget_count }
}
}
);
});
Upvotes: 0
Reputation: 693
Have a look at this explanations of versionKey property (if you haven't already)
http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning
The example from the article looks similar to yours except that they are modifying array items (comments) and you are pushing new item to widgets array. But as I understood if you use mongoose v3+ and perform save() operation, this will do all necessary operations with versionKey for you.
So if you will do something like:
model.findById(doc._id, function(err, doc) {
// handle error
doc.widgets.push({ widget: widget_id, count: widget_count });
doc.save(callback);
});
then save() operation should internally looks like this:
doc.update(
{ _id: doc._id, __v: doc.__v },
{
$push: {
widgets: { widget: widget_id, count: widget_count }
},
$inc: {
__v: 1
}
}
);
So maybe you should make sure you use mongoose v3+ and do push() and then save() or is it how you did this stuff initially?
I haven't tested this, just wanted to share my search results and thoughts with you in case this can help somehow.
Upvotes: 1