Mon go VersionError состояние гонки - найти, изменить и .save () - PullRequest
0 голосов
/ 18 апреля 2020

Я упрощаю свои модели Mon goose следующим образом: скажем, у меня есть модель Bank с поддокументами Users, каждая из которых имеет массив Transfers

    BankSchema = {
     bank_name : {type:String},
     users : [
              {
                user_name : {type:String},
                transfers : [
                              {
                                amount : {type:Number},
                                date   : {type:Date}
                              }
                            ]
               }
             ]
    }

В BankSchema есть метод добавления переводов, который находит нужного пользователя и добавляет к нему перевод

BankSchema.methods.addTransfer(user_name, new_transfer)
{
 var bank = this;
 for(let u in bank.users)
  {
   if(bank.users[u].name == user_name)
    { 
     bank.users[u].transfers.push(new_transfer); 
     break;
    }
  }
 return bank.save(); // promise
}

Теперь, скажем, у меня есть CSV-переводы различных банков для импорта, поэтому я делаю

/*
 csv will give rows like {bank_id:'', user_name:'', transition:{} }
*/

for(let i in csv)
{
 var row = csv[i];
 Bank.findById(row.bank_id)
   .then(function(bank)
       {
        // addTransfer also save() the document
        bank.addTransfer(row.user_name, row.transition);
       })
   .catch(function(err)
      {
       console.error(err); 
       // this gives:  VersionError: No matching document found for...
      })
}

В л oop каждый раз, когда я нахожу банк, изменяю его и сохраняю. Поэтому я не изменяю несколько раз параллельно одну и ту же версию, но каждый раз повторяю ее. Я думал, что этого было достаточно, чтобы избежать ошибки Mon go VersionError, но, вероятно, я ошибся.

Разве невозможно одновременное добавление вложенных документов?

"mongoose": "^5.4.20",
$npm --version 6.4.1

======= ОБНОВЛЕНИЕ 1 =======

После обсуждения с Олегом (см. Его ответ), я думаю, просто обработайте эту ошибку и попробуйте снова. Помимо массового импорта, во время выполнения разные пользователи могут добавлять передачи одновременно. Но они должны быть довольно редкими ситуациями, так что попытка снова может быть решением? Что-то вроде:

function main() 
{
 for(let i in csv)
  {
    var row = csv[I];

    // in parallel, not blocking
    addTransferToBank(row.bank_id, row.user_name, row.transition); 
   }
}

function addTransferToBank(bank_id, user_name, transition)
{
 var deferred = Q.defer();
 Bank.findById(bank_id)
   .then(function(bank)
       {
        // addTransfer also save() the document
        return bank.addTransfer(user_name, transition);
       })
   .then(function()
       {
         deferred.resolve(true); // ok, done
       })
   .catch(function(err)
      {
            if(err && err.name && err.name == "VersionError")
                {
                 // TRY AGAIN
                 deferred.resolve(addTransferToBank(bank_id, user_name, transition)); // I could also run it after a timeout
                }
            else
                { deferred.reject(err);  }
      })
return deferred.promise;
}

1 Ответ

0 голосов
/ 18 апреля 2020

Вам нужно дождаться разрешения, которое вы возвращаете из addTransfer, чтобы перейти к следующей передаче.

Если это не работает:

    return bank.addTransfer(row.user_name, row.transition);

... вам, возможно, придется подождать этого явно, используя другой механизм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...