How to read / write a parallel document using mongoDB / mongoose

I am using MongoDB with NodeJS. Therefore, I use mongoose.

I am developing a real-time multiplayer game. Therefore, I receive many requests from many players, sometimes at the same time.

I can simplify this by saying that I have a home collection that looks like this:

{
    "_id" : 1,
    "items": [item1, item2, item3]
}

I have a static function called after each request:

house.statics.addItem = function(id, item, callback){
    var HouseModel = this;
    HouseModel.findById(id, function(err, house){
        if (err) throw err;
        //make some calculations such as:
        if (house.items.length < 4){
            HouseModel.findByIdAndUpdate(id, {$push: {items: item}}, cb);
        }
    });
}

In this example, I have encoded so that there are housenever more than 4 elements in a document . But it happens that when I receive several requests at the same time, this function is executed twice on both requests, and since it is asynchronous, they both click on a new element in the element field, and then my house has 5 elements.

- ? ?

+1
4

, houseModel, , addItem .

, findById house.items.length, () . nodejs ; , .

, . addItem bump the want "" .

+2

, Mongoose 4.10.8 , save() , . # 4004:

@vkarpov15 :

8b4870c ,

Mongoose 4.10.8, this.$where. , (.. this.isNew), , MongoDB , . , schemas saveErrorIfNotFound , save() , .

- (, ) , " concurrency" ( # 4004). I.e., , findOne(), , save(), if (ex) retry(). , , , , Mongooses , , ( -, Mongooses, .update()), (.. save(), ).

, , , npm, .

+1

. , , , :

class NpcSaveQueue {
    constructor() {
        this.queue = new Map();
        this.runQueue();
    }

    addToQueue(unitId, obj) {
        if (!this.queue.has(unitId)) {
            this.queue.set(String(unitId), obj);
        } else {
            this.queue.set(String(unitId), {
                ...this.queue.get(unitId),
                ...obj,
            })
        }
    }

    emptyUnitQueue(unitId) {
        this.queue.delete(unitId);
    }

    async executeUnitQueue(unitId) {
        await NPC.findByIdAndUpdate(unitId, this.queue.get(unitId));
        this.emptyUnitQueue(unitId);
    }

    runQueue() {
        setInterval(() => {
            this.queue.forEach((value, key) => {
                this.executeUnitQueue(key);
            })
        }, 1000)
    }
}
Hide result

, NPC, Mongoose, :

npcSaveQueue.addToQueue(unit._id, {
                "location.x": newLocation.x,
                "location.y": newLocation.y,
            });

, SaveQueue NPC, .

0

This function is never performed twice because the update operation is atomic at the same document level. Further information in the official guide: http://docs.mongodb.org/manual/core/write-operations-atomicity/#atomicity-and-transactions

-2
source

All Articles