2011-05-22 3 views
15

У меня есть коллекция сообщений:Есть ли способ атомного обновления двух коллекций в MongoDB?

{ 
    messageid: ObjectId 
    userid: ObjectId 
    message: string 
    isread: true|false 
} 

и набор сообщений подсчитывает для каждого пользователя:

{ 
    userid: ObjectId 
    total: int 
    unread: int 
} 

Когда я удалю сообщение от «сообщения» сбор, мне также нужно уменьшить «общего »в коллекции« counts »и условно (если« messages.isread »== false) также уменьшает« непрочитанное »поле.

Для этого мне нужно сначала получить сообщение, проверить его поле «isread», а затем обновить подсчеты. Существует вероятность того, что сообщение будет помечено как прочитанное между этими действиями, тогда я уменьшу «непрочитанные» подсчеты неправильно.

Есть ли способ условно изменить что-то в одной коллекции по результатам другой коллекции за один выстрел?

ответ

11

Есть много ответов, но я хочу, чтобы заполнить все пробелы здесь:

Есть ли способ атомарно обновить две коллекции в MongoDB?

Нет. Атомное обновление двух коллекций является фактически сделкой. MongoDB не поддерживает транзакции через коллекции или даже внутри коллекции.

MongoDB предоставляет several modifiers, которые являются атомарными в одном документе.Таким образом, вы можете увеличивать сразу несколько разных переменных ($inc). Хотя здесь есть некоторые ограничения, вы не можете выполнять две разные операции над одним свойством.

Есть ли способ условно изменить что-то в одной коллекции по результатам другой коллекции за один выстрел?

В общем, есть некоторые документы на atomic updates. Однако вам действительно нужна очередь и некоторая форма two-phase commit или вам нужны триггеры.

Триггеры имеют not yet been implemented, поэтому на самом деле это не вариант в вашем случае.

Существует вероятность того, что сообщение будет отмечено как прочитанное между этими действиями, тогда я уменьшу количество непрочитанных ошибок.

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

0

Вы можете сделать это с помощью триггера в sql. Но в манго нет триггера.

Вы можете выполнить операцию на одном из документа и проверить LastErrorMessage на этой операции, установив SafeMode.True

Тогда, если нет ошибок, то не обновлять вторую коллекцию.

В настоящее время нет никакого способа сделать это атомным путем.

Если есть, я бы использовал в своем проекте. Мне тоже нужна была эта функциональность.

1

Нет, к сожалению, это невозможно. MongoDB поддерживает только atomic operations в рамках одного документа. Невозможно выполнить транзакционную операцию по нескольким документам, даже если они находятся в одной коллекции.

4

Вы не можете удалить документы из двух коллекций одновременно. Что вы можете сделать, так это использовать findAndModify(), чтобы удалить документ, чтобы получить его точное состояние до его удаления. Это позаботится о вашей непрочитанной проблеме с расчетом.

1

MongoDB очень быстр, поэтому, если ваш сайт не является высокой нагрузкой, вы можете просто пересчитать общее количество сообщений и общее количество сообщений, прочитанных по каждому запросу. Поместите только индекс на isread. Граф кажется очень быстрым даже на большом объеме данных.

Фактически, ваши полные и непрочитанные поля - это просто кеши. Вам это действительно нужно?

Существует вопрос о подобной проблеме здесь: MongoDB: Calling Count() vs tracking counts in a collection

+0

Это тоже был мой вопрос :) Мой сайт будет сравнительно высокой нагрузкой, и я не хочу пересчитывать статистику каждый раз, когда они мне нужны, поэтому я использую эту коллекцию счетчиков. – Andrey

+0

Вы должны просмотреть его, если вы еще этого не сделали. – Maxence

+0

Даже без профилирования я могу сказать, что cursor.count() всегда будет намного медленнее, чем просто получить число, особенно на наборах сотен миллионов записей. – Andrey

Смежные вопросы