Why are there two copies of the state?
Hmm, why would the User need to hold a list of channels its participating in? This is not objectively state of the user, but of the situation that the user is in. It does make sense for a channel to be aware of Users, if only because a channel to no-where makes little sense.
My first thought would be to remove the channel list from the user. If you need to list up all channels, mongo does provide indecies over multi-valued properties of the document collection.
Two copies. What can be done?
If for whatever reason the channel list must exist in the user document and an equivalent user list in the channel, I would apply double-binding, or half-binding.
In Double binding both the Channels in the User, and the Users in the Channel must be verified against each other. Should both documents concur that a Given user is a member of a given channel, then the user is a member, otherwise its not. Unfortunately this requires N documents for verification.
In Half-binding pick either the channels, or the users to store an authoritative copy, and the others store an indicative copy. The indicative copy must be verified against the authoritative, while the authoritative stands alone. Unfortunately this does mean that there may exist an authoritative record that states membership, while the indicative copies do not know of this authoritative membership. This will necessitate a lookup (via index) for any unknown authoritative records to complete the listing. In short the indicative copy is a cache of how the system was, if regenerating the view is expensive this might be acceptable with an eventual consistency.
How about Three documents?
Considering that these two lists essentially represent the same data from different perspectives, why don't you model it as a relationship? Create a document that binds a user to a given channel. Deleting the document is atomic.
- Need a list of Channels for a user, list by UserID.
- Need a list of Users for a channel, list by ChannelID.
Now remove the channel/user lists from the original documents. If need be on request generate
the channel/user list and embed it in the larger document and/or extract the channel/user list and update those separate documents in line with channel/user saving.
Its relational, so why not a Relational Database?
While I know the fashion these days are for document stores, there is something to be said about transactions in relational stores when it comes to relational
data.