Есть ли способ атомного обновления двух коллекций в MongoDB?
У меня есть набор сообщений:
{
messageid: ObjectId
userid: ObjectId
message: string
isread: true|false
}
и набор сообщений для каждого пользователя:
{
userid: ObjectId
total: int
unread: int
}
Когда я удаляю сообщение из коллекции "сообщений", мне также необходимо уменьшить "total" в коллекции "counts" и условно (если "messages.isread" = false) также уменьшает "непрочитанное" поле.
Для этого мне нужно сначала получить сообщение, проверить его "isread", а затем обновить подсчеты. Существует вероятность того, что сообщение будет помечено как прочитанное между этими действиями, тогда я уменьшу "непрочитанные" подсчеты неправильно.
Есть ли способ условно изменить что-то в одной коллекции на основе результатов другой коллекции за один снимок?
Ответы
Ответ 1
Здесь есть много ответов, но я хочу заполнить все пробелы здесь:
Есть ли способ атомного обновления двух коллекций в MongoDB?
Нет. Атомное обновление двух коллекций фактически является транзакцией. MongoDB не поддерживает транзакции между коллекциями или даже внутри коллекции.
MongoDB предоставляет несколько модификаторов, которые являются атомарными в одном документе. Таким образом, вы можете увеличивать сразу несколько разных переменных ($inc
). Хотя здесь есть некоторые ограничения, вы не можете выполнять две разные операции над одним свойством.
Есть ли способ условно изменить что-то в одной коллекции на основе результатов другой коллекции за один снимок?
В документе atomic updates есть некоторые документы. Однако вам действительно нужна очередь и некоторая форма двухфазная фиксация или вам нужны триггеры.
Триггеры еще не реализованы, поэтому это не действительно вариант в вашем случае.
Существует вероятность, что сообщение будет помечено как прочитанное между этими действиями, тогда я уменьшу количество непрочитанных ошибок.
На этом этапе у вас есть несколько различных стратегий для того, чтобы заставить себя вести себя с некоторым уровнем согласованности. Честно говоря, на основе вашего описания вы можете исследовать создание простой очереди, которая обновляет ваши итоги.
Ответ 2
Вы не можете удалить документы из двух коллекций в тот же момент. Что вы можете сделать, так это использовать findAndModify(), чтобы удалить документ, чтобы получить его точное состояние до его удаления. Это позаботится о вашей непрочитанной проблеме подсчета.
Ответ 3
Нет, к сожалению, это невозможно. MongoDB поддерживает атомные операции в рамках одного документа. Невозможно выполнить транзакционную операцию по нескольким документам, даже если они находятся в одной коллекции.
Ответ 4
MongoDB работает очень быстро, поэтому, если ваш сайт не является высокой нагрузкой, вы можете просто пересчитать общее количество сообщений и общее количество сообщений, прочитанных по каждому запросу. Поместите только индекс на isread. Граф кажется очень быстрым даже на большом объеме данных.
Фактически, ваши полные и непрочитанные поля - это просто кеши. Вам это действительно нужно?
Здесь возникает вопрос о подобной проблеме: MongoDB: Calling Count() против отслеживания в коллекции
Ответ 5
Вы можете сделать это с помощью триггера в sql. Но в манго нет триггера.
Вы можете выполнить операцию над одним из документов и проверить для LastErrorMessage эту операцию, установив SafeMode.True
Затем, если нет ошибки, обновите вторую коллекцию.
В настоящее время нет способа сделать это по-атомному.
Если есть, я бы использовал в своем проекте. Мне тоже нужна была эта функциональность.