Я упрощаю свои модели 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;
}