Question

Let's say I have a schema A in mongoose. It looks like this:

{
    arr: [{
        num: Number,
        text: String
    }]
}

Now I want to perform the following action:

  1. Select an A namely a.

  2. Get the actual count of a.arr's items.

  3. Add a new element to a.arr, with the count and a text.

My implementation:

A.findOne({_id: someId}, function(err, a) {
    var count = a.arr.length;
    a.push({
        count: count,
        text: 'some text'
    });
    a.save(...)
});

Works fine so far. But my problem: If I execute that concurrent, let's say with 5 processes, some processes execute findOne before the others saved. So count is 0 for the first few, and then when they have saved, it gets immediately 3 or 4 for the next processes.

But I want that to execute serial.

How to achieve that?

Thanks!

Was it helpful?

Solution

There is no transaction support in mongo, but you could implement two phase commits as described in http://cookbook.mongodb.org/patterns/perform-two-phase-commits/

Alternatively you could implement some coordination between processes, fx assign data ranges to specific processes if data supports this scenario.

Edit: in very simple form you could implement some optimistic document locking by adding property lockProcessId and use following command sequence:

db.A.findAndModify({_id: someId, lockProcessId:{$exists:false}},{$set:{lockProcessId: someProcessId},{new:true}}

db.A.findAndModify({_id: someId, lockProcessId:someProcessId},{$push:{arr:{ count: count,text:'some text'}},$unset:{lockProcessId:1}})

If first query returns nothing, process should skip this document, otherwise it should run second query

However if some process dies in the middle you could have some documents locked, probably you need some scheduler to clear locked states.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top