Является ли перемещение документов между коллекциями хорошим способом представления изменений состояния в MongoDB?

#mongodb

#mongodb

Вопрос:

У меня есть две коллекции, одна (A), содержащая элементы, подлежащие обработке (относительно небольшие), и одна (B) с уже обработанными элементами (довольно большая, с дополнительными полями результатов).

Элементы считываются из A, обрабатываются и сохраняют ()’d в B, затем удаляют ()’d из A.

Обоснование заключается в том, что индексы у них могут отличаться, и что таким образом «входящая» коллекция может быть очень маленькой и быстрой.

Я столкнулся с двумя проблемами с этим:

  • если либо время ожидания remove (), либо save (), либо иной сбой при загрузке, я полностью теряю элемент или обрабатываю его дважды
  • если оба выходят из строя, возникают побочные эффекты, но записи об этом нет

Я могу обойти случай двойного сбоя с помощью блокировок findAndModify (в противном случае они не нужны, у нас блокировка на уровне процесса), но тогда у нас возникают проблемы с устаревшей блокировкой, и частичные сбои все еще могут произойти. Насколько я могу судить, нет способа атомарно удалить сохранить в разные коллекции (возможно, по дизайну?)

Существует ли наилучшая практика для этой ситуации?

Ответ №1:

Насколько я могу судить, нет способа атомарно удалить сохранить в разные коллекции (возможно, по дизайну?)

Да, это сделано специально. MongoDB явно не предоставляет объединения или транзакции. Удалить Сохранить — это форма транзакции.

Существует ли наилучшая практика для этой ситуации?

Здесь действительно есть два варианта низкой сложности, оба предполагают findAndModify .

Вариант № 1: единая коллекция

Основываясь на вашем описании, вы в основном создаете очередь с некоторыми дополнительными функциями. Если вы используете одну коллекцию, то вы используете findAndModify для обновления статуса каждого элемента по мере его обработки.

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

Вариант # 2: две коллекции

Другой вариант — это в основном двухфазная фиксация с использованием findAndModify .

Взгляните на документы для этого здесь.

Как только элемент обрабатывается в A, вы устанавливаете поле, помечающее его для удаления. Затем вы копируете этот элемент в B. После копирования в B вы можете удалить элемент из A.

Комментарии:

1. Я на самом деле пришел к существенно более простой версии реализации двухфазной фиксации с откатами, еще немного почесав голову, рад узнать, что это официальный способ 🙂 Блокировка с одной коллекцией не совсем работает из-за различных способов использования элементов, подлежащих обработке, по сравнению с уже обработанными (рекурсивные / безотказные блокировки findAndModify были бы здесь очень плохими). Это двухфазный процесс!

Ответ №2:

Я еще не пробовал это сам, но в новой книге «50 советов и хитростей для разработчиков MongoDB» несколько раз упоминается об использовании заданий cron (или служб / планировщика) для очистки подобных данных. Вы могли бы оставить документы в коллекции помеченными для удаления и запускать ежедневное задание для их очистки, уменьшая общий объем исходной транзакции.

Из того, что я узнал до сих пор, я бы никогда не оставил базу данных в состоянии, в котором я полагаюсь на выполнение следующего действия базы данных, если это не последнее действие (ведение журнала повторно отправит последнее действие базы данных после восстановления). Например, у меня есть трехэтапный процесс регистрации учетной записи, в котором я создаю пользователя в CollectionA, а затем добавляю другой связанный документ в CollectionB. Когда я создаю пользователя, я встраиваю детали документа CollectionB в CollectionA на случай, если вторая запись завершится неудачей. Позже я напишу процесс, который удаляет внедренные данные из CollectionA, если документ в CollectionB существует

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

Комментарии:

1. Вы знаете, читая мой собственный комментарий, это кажется неудовлетворительным решением. Создание новой учетной записи — одна из наиболее важных частей веб-приложения, и в моем случае это неизбежно многоступенчатое обновление. Я рассматриваю возможность использования dapper для sql Express или mysql для базовой системы. А для отчетов / архивирования / форума я бы использовал mongo

2. Выполнение cronjobs очистки и скрытие резервных копий внутри других структур не совсем похоже на чистое решение (хотя я не могу придумать лучшего для вашего случая — откат создания пользователя на самом деле не вариант — кроме небольшого варианта записи в качестве элемента «job» сначала в коллекцию C, затем создания записей в A и B и удаления / маркировки C уникальными индексами в A / B)

3. Ах, вы имеете в виду что-то вроде коллекции (C) заданий, которые необходимо выполнить, и флага для указания стадии, на которой они находятся, чтобы их можно было завершить чисто. Мне это тоже не кажется чистым, поэтому я начинаю отходить от Mongo для этого конкретного проекта