2014-08-30 2 views
4

У меня есть большая логическая проблема с использованием Node/Mongoose/Socket.io ... Предположим, у меня есть модель сервера, которую часто называют одновременно в моем приложении, некоторые вызовы включают обновление данных в модели.Mongoose асинхронные конфликты с несколькими конфликтами

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

     catches.error(error); 

     if (server !== null) { 

       server.anything = "ahah"; 

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

     } 

    } 

Иногда 2 люди будут называть это в то же самое время, в то время как первый человек будет экономить() другой парень может уже findOne «сервер» и получил «старый объект», который не является до -to-date и сохранить().

Большая проблема здесь, когда второй парень сохранит() «сервер» («старый объект»), он буквально перепишет изменения первого ... Вы можете представить, какие большие конфликты он создаст по моему заявлению.

Я думал об изменении всех методов save() для обновления(), которые устраняют проблему, но в какой-то момент в проекте очень сложно использовать update() напрямую, а не как практично.

Есть ли способ «заблокировать» вызов findOne(), когда кто-то его обновляет? Например, когда вы находитеOne(), вы также говорите «эй, я скоро это обновлю, поэтому не позволяйте людям находить это прямо сейчас» (с Mongoose или даже MongoDb)

Это было какое-то время, когда я ищу, t найти ответ :(

Надеюсь, вы поняли мою проблему;) спасибо!

+1

Nope. См. Http://stackoverflow.com/questions/11076272/its-not-possible-to-lock-a-mongodb-document-what-if-i-need-to – JohnnyHK

+0

, тогда как вы можете создать сайт с людьми на нем с монго? ... – Laurent

+0

Вы структурируете свою схему так, чтобы все ваши модификации документа могли быть выполнены с использованием атомных 'update' вызовов. – JohnnyHK

ответ

2

Как вы можете здесь рассказать, это не лучший способ обработки обновлений обработки ваших данных. Если вы считаете, что вы просите сделать это, по существу, сводится к:

  1. Извлечь объект из базы данных.
  2. Обновить объект в коде.
  3. Сохраните эти данные без гарантии что-то еще изменившее его.

Поэтому, когда это возможно, вам необходимо избегать этого шаблона и следовать здравому смыслу, что вам просто нужно изменить существующее значение, если оно в настоящее время не установлено на это значение. Таким образом, это означает, что только обрабатывает «обновить» тип заявления с оператором, такими как $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 

     } 
    } 
); 

Это означает, что вы выбрасывая любые проверки поля или другие сохранить крючки для мангустов, но это «атомный «форма обновления в том, что чтение и запись не являются отдельными операциями, как вы сейчас реализуете.

Если вы хотите реализовать некоторый тип «блокировки», то подобный подход - ваш лучший способ сделать это. Поэтому, если вы хотите установить «состояние» в документе, чтобы показать, что кто-то в настоящее время его редактирует, затем создайте поле для этого и создайте его в своих запросах.

Для «чтения» документ и получить информацию, которую вы хотите представить на «редактировать», то вы могли бы сделать что-то вроде этого:

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

    } 
); 

Это означает, как кто-то «захватывает» правку то последующее операции не смогут этого сделать, поскольку они ищут документ, состояние которого заблокировано false, и его больше нет.Тот же принцип применяется при совершении правки в виде «сохранить», только в обратном порядке:

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

    } 
); 

Вы всегда можете сделать более сложные вещи, такими как сохраненные исправления или ожидают номер версии с операциями или любой другой формой обработки. Но, вообще говоря, вы должны управлять этим самостоятельно в соответствии с вашими потребностями.

+0

Единственная проблема с последним решением заключается в том, что если другому парню действительно нужно изменить данные «после», первый изменил его, «заблокированное» состояние сократит процесс, и это может привести к другим конфликтам. В любом случае, хороший трюк, я изменю свой код и попытаюсь использовать mongo таким образом;) – Laurent

0

Я только что понял, что я опубликовал аналогичное сообщение о переполнении стека. Вы можете найти сообщение здесь: How to read/write a document in parallel execution with mongoDB/mongoose

В этом сообщении кто-то сказал мне сохранить somedate в памяти, чтобы избежать такого поведения. Это то, что я сделал, и он отлично работает. Но если вы используете многопроцессорный процесс, вам нужно найти способ обмена памятью между процессами.

Смежные вопросы