javascript - Mongoose asynchronous multiple save conflicts - Stack Overflow

I've a big logic problem using NodeMongooseSocket.io ... Let's say I got a Server model whi

I've a big logic problem using Node/Mongoose/Socket.io ... Let's say I got a Server model which is often called at the same time in my application, some calls involve updating datas in the model.

    db.Server.findOne({_id: reference.server}).exec(function(error, server) {

        catches.error(error);

        if (server !== null) {

              server.anything = "ahah";

              server.save(function(error) { });

        }

    }

Sometimes, 2 people will call this at the same time, while the first person will save() the other guy could already have findOne the "server" and got the "old object" which isn't up-to-date and save() it.

The big problem here is when the second guy will save() the "server" (the "old object") it will literally overwrite the changes of the first one ... You can imagine the big conflicts it will create on my application.

I thought about changing all the save() methods to update() which get rid of the problem but at some point in the project it's very tricky to use the update() directly, and not as practical.

Is there a way to "lock" the findOne() call while someone is updating it ? Like when you findOne() you also say "hey i will update this soon so don't let people find it right now" (with Mongoose, or even MongoDb)

It's been a while i'm searching i don't find any answer :(

Hope you understood my problem ;) thank you !

I've a big logic problem using Node/Mongoose/Socket.io ... Let's say I got a Server model which is often called at the same time in my application, some calls involve updating datas in the model.

    db.Server.findOne({_id: reference.server}).exec(function(error, server) {

        catches.error(error);

        if (server !== null) {

              server.anything = "ahah";

              server.save(function(error) { });

        }

    }

Sometimes, 2 people will call this at the same time, while the first person will save() the other guy could already have findOne the "server" and got the "old object" which isn't up-to-date and save() it.

The big problem here is when the second guy will save() the "server" (the "old object") it will literally overwrite the changes of the first one ... You can imagine the big conflicts it will create on my application.

I thought about changing all the save() methods to update() which get rid of the problem but at some point in the project it's very tricky to use the update() directly, and not as practical.

Is there a way to "lock" the findOne() call while someone is updating it ? Like when you findOne() you also say "hey i will update this soon so don't let people find it right now" (with Mongoose, or even MongoDb)

It's been a while i'm searching i don't find any answer :(

Hope you understood my problem ;) thank you !

Share Improve this question edited Jun 27, 2017 at 11:15 Neil Lunn 151k36 gold badges355 silver badges325 bronze badges asked Aug 30, 2014 at 2:54 LaurentLaurent 2,1783 gold badges23 silver badges45 bronze badges 9
  • 1 Nope. See stackoverflow./questions/11076272/… – JohnnyHK Commented Aug 30, 2014 at 3:40
  • then how can you build a website with people on it with mongo ? ... – Laurent Commented Aug 30, 2014 at 3:41
  • You structure your schema so that all of your doc modifications can be done using atomic update calls. – JohnnyHK Commented Aug 30, 2014 at 3:42
  • 1 Keep in mind that Mongoose does implement save using an atomic update call that only $sets the fields in your doc that you've actually changed so it's not as bad as you're probably thinking. It's array manipulation that gets you in the most trouble (which is why Mongoose added versioning), but you need to be conscious of what's going on regardless. – JohnnyHK Commented Aug 30, 2014 at 13:46
  • 1 this needs more attention from beginner MEAN developers. – Sunny R Gupta Commented May 5, 2016 at 5:15
 |  Show 4 more ments

2 Answers 2

Reset to default 4

As you can tell here, this is not the best way to handle processing updates on your data. If you consider what you are asking to do it essentially boils down to :

  1. Fetch an object from the database.
  2. Update a property in code.
  3. Save that data back with no guarantee something else modified it.

So where possible you need to avoid that pattern and follow the mon sense that you just need to change an existing value where it is presently not set to that value. So this means just processing an "update" type of statement with an operator such as $set:

db.Server.findOneAndUpdate(
    { "_id": refernce.server, "anything": { "$ne": "ahah" } },
    { "$set": { "anything": "ahah" } },
    function(err,server) {
       if ( server != null ) {

          // then something was actually found and modified
          // so server now is the updated document

       }
    }
);

This means you are throwing away any field validation or other save hooks for mongoose, but it is an "atomic" form of update in that reading and writing are not separate operations, which is how you are currently implementing.

If you are looking to implement some type of "locking" then a similar approach is your best way to do this. So if you want to set a "state" on a document to show that someone is currently editing it, then maintain a field to do so and build it into your queries.

For "reading" a document and getting the information that you want to present to an "edit" then you would do something like this:

db.Server.findOneAndUpdate(
    { "$_id": docId, "locked": false },
    { "$set": { "locked": true } },
    function(err,document) {

    }
);

Which means as someone "grabs" the edit then subsequent operations would not be able to do so since they are looking to retrieve a document whose locked state is false, and it no longer is. The same principle applies when mitting your edit as a "save", just in reverse:

db.Server.findOneAndUpdate(
    { "$_id": docId, "locked": true },
    { "$set": { "locked": false } },
    function(err,document) {

    }
);

You can always do more advanced things such as saved revisions or expecting a version number with operations or any other form of handling. But generally speaking, you should be managing this yourself according to your needs

I just realized I posted a similar post on stack overflow. You can find the post here: How to read/write a document in parallel execution with mongoDB/mongoose

In this post someone told me to keep somedate in memory to avoid this behavior. This is what I did and it works great. But if you are using multi process you need to find a way to share memory between processes.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744265491a4565847.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信