How can make sure whole "delete person +cascade delete on cities" as an atomic operation in MongoDB?
As others have said MongoDB has a client side version of two phase commit, however this:
- Does not provide the two phase transactional commit
- Is not atomic
- Has considerable overhead
- Is client side (which actually rebuffs any benefit you get from this being server-side, i.e. with fails)
- And cannot provide saftey of information and transactions in the event of a failure
That being said if you can rely on your application being to write to the database and not failing then the MongoDB edition of a two phase commit could work here; however, then why are you not just doing one query after the other instead of adding the extra overhead of using fake two phase commits.
It is, normally, assumed that one can write to mongodb if one of the delete queries succeed however in the event they do not most "mark" the parent row of the cascade as deleted or something and has a dedicated cronjob which comes back later and cleans it all up in a manner that is consistent (since to do that there and then would delay the client).
As for which schema design is best, it is not true that embedding is preferred. I have noticed that you say:
then I want to update people array in Cities
Which would require most likely a $pull
or something similar to be used on that array. I should note that if that array grows considerably that the in-memory operation of $pull
will be somewhat slower than querying two separate collections.
At the end of the day, we cannot really advise on your schema design because we don't know enough so I will just leave it at that.
Edit
Though both of the other answers do make a point. If you embed the city_id
into the person document you can actually cascade the relation in a single call. Of course this is a odd one off, normally you might have too many children records to fit into a Mongo doocument but this scenario fits.