Подтвердить что ты не робот

Ошибка "Ошибка версии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)
4b9b3361

Ответ 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));