I have a collection of messages:
{
messageid: ObjectId
userid: ObjectId
message: string
isread: true|false
}
and a collection of message counts per user:
{
userid: ObjectId
total: int
unread: int
}
When I delete a message from “messages” collection, I also need to decrease “total” in “counts” collection, and conditionally (if “messages.isread” == false) decrease “unread” field as well.
For that I need to first retrieve teh message, check its “isread” field, and then update the counts. There is a possibility that the message will be marked as read in between those actions, then I will decrease “unread” counts incorrectly.
Is there a way to conditionally change something in one collection based on results of other collection in one shot?
There are lots of answers here, but I want to fill in all of the blanks here:
No. Atomic update of two collections is effectively a transaction. MongoDB does not support transactions across collections or even within a collection.
MongoDB provides several modifiers that are atomic on a single document. So you can increment several different variables at once (
$inc). Though there are some limitations here, you cannot perform two different operations on a single property.There are some documents here on atomic updates in general. However, what you really need is a queue and some form of two-phase commit or you need triggers.
Triggers have not yet been implemented, so it’s not really an option in your case.
At this point, you have a couple of different strategies for making this behave with some level of consistency. Frankly, based on your description, you may want to investigate building a simple queue that updates your totals.