Ошибка "Ошибка версииError: Нет совпадающего документа" на Node.js/Mongoose
Я относительно новичок в Node.js и Mongo/Mongoose, и у меня очень трудное время устраняет неполадки в конкретной ошибке Mongoose:
VersionError: Совпадающий документ не найден.
(Вся трассировка ошибок/стек в нижней части этого вопроса.)
Это сообщение в блоге довольно четко описывает, как может возникнуть проблема с версией:
(TL; DR - "Mongoose v3 теперь добавляет к каждому документу ключ конфигурации, конфигурируемый с помощью схемы.Это значение атомарно увеличивается, когда модификация массива потенциально меняет положение элементов массива". Если вы попытаетесь сохранить документ, но ключ версии больше не совпадает с объектом, который вы получили, вы получаете выше VersionError
.)
Основной вопрос: Есть ли способ показать оскорбительную операцию save()
? Или какой документ не удалось сохранить? Или что-нибудь вообще?!;)
Задача:. Это относительно большая база кода со многими массивами, и я не уверен, как начать устранение этой проблемы. В частности, ошибка trace/stack НЕ показывает, где проблема существует. См. Ниже:
VersionError: No matching document found.
at handleSave (<project_path>/node_modules/mongoose/lib/model.js:121:23)
at exports.tick (<project_path>/node_modules/mongoose/lib/utils.js:408:16)
at null.<anonymous> (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js:484:9)
at g (events.js:192:14)
at EventEmitter.emit (events.js:126:20)
at Server.Base._callHandler (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:391:25)
at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:558:20)
at MongoReply.parseBody (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:131:5)
at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:517:22)
at EventEmitter.emit (events.js:96:17)
Ответы
Ответ 1
По запросу, вот контур нашей проблемы и как мы ее разрешили:
В нашей системе мы создали обычную процедуру блокировки документов (с использованием redis-lock), в которой следующее произошло в этом точном (неправильном) порядке:
НЕПРАВИЛЬНЫЙ ПОРЯДОК ОПЕРАЦИЙ:
- Полученный запрос клиента
- Документ заблокирован
- Полученный документ
- Документ отредактирован
- Документ разблокирован
- Клиент запрошен.
- Сохраненный документ
Как только вы увидите это, проблема очевидна: мы сохраняем наши документы за пределами нашей блокировки документа.
Предположим, что # 6 занимает 100 мс в нашей системе. Это окно размером 100 мс, в котором, если любые другие запросы захватывают тот же документ, у нас будет конфликт с сохранением (в этом вопросе ошибка с именем в основном является конфликтом сохранения IMHO).
Другими словами/пример: в нашей системе Request A grabbed Version 1 of Document X отредактировал его, а затем разблокировал, но до того, как Request A сохранил документ, запросить B захваченный документ X и увеличил его до версии 2 (read на монгольских версиях для получения дополнительной информации об этом). Затем Request A решает свой запрос клиента и отправляется на сохранение документа X, но он пытается сохранить версию 1, и теперь он видит, что имеет версию 2 и, следовательно, ошибку выше.
Итак, исправление легко. Сохраните документы в своей блокировке. (В приведенном выше примере переместите # 7 до # 5. См. Ниже.)
ПРАВИЛЬНЫЙ/ФИКСИРОВАННЫЙ ПОРЯДОК ОПЕРАЦИЙ
- Полученный запрос клиента
- Документ заблокирован
- Полученный документ
- Документ отредактирован
- Сохраненный документ
- Документ разблокирован
- Клиент запрошен.
(Вы можете сделать аргумент, что # 6 и # 7 должны быть заменены, но это выходит за рамки Mongo/Mongoose/this question.)
Я собираюсь оставить этот вопрос ненадолго и посмотреть, сможет ли кто-нибудь пролить свет на лучший способ изолировать соответствующий код и устранить эту проблему. В нашем случае это была очень системная проблема, и ОЧЕНЬ было сложно устранить наши навыки в то время.
Ответ 2
Он позволяет указывать на сохранение одного и того же документа одновременно, как указывает robertklep.
У нас была аналогичная проблема с одновременным сохранением одного документа с использованием async.parallel.
Ответ 3
Эта ошибка также может возникать, когда ваш процесс поддерживает устаревшую версию документа в памяти, а затем пытается сохранить его в какой-то момент после того, как он был обновлен другим процессом.
Ответ 4
У меня была эта проблема в приложении NextJS/Express, но после прочтения это обсуждение Mongoose, я обнаружил, что могу решить проблему просто удалить свойство __v
из документа, который я пытался сохранить:
const fixedDocument = _.pickBy(originalDocument, (val, key) => key !== '__v');
Ответ 5
Я имел этот вопрос, потому что я был удаления элемента из массива документа с использованием splice
функции.
Я исправил замену функции splice
функцией pull
из мангуста.
Ответ 6
У меня была такая же ошибка, когда я пытался обновить идентификаторы ссылок пользователя на электронную почту. Исправление было действительно простым с async/await! Вот фрагмент кода, надеюсь, это поможет.
email
.save()
.then(() =>
User.findById(email.from).then(async sender => { // declare function as async
sender.emails.sent.push(email._id);
await sender.save(); // wait for save() to complete before proceeding
}).catch((err) => console.log(err))
)
.then(() =>
User.findById(email.to).then(async receiver => { // same as above
receiver.emails.received.push(email._id);
await receiver.save(); // same as above
}).catch((err) => console.log(err))
)
.then(() => res.status(200).json({ message: successMessage }))
.catch(err => console.log(err));