2

As a newbie to CouchDB or NoSQL in general I can't find a good way of updating two documents, with guarantee that either both are updated or none of them.

In my use case there is a boolean flag in each document. To illustrate, lets assume I'm talking about document of type="citizen" with a boolean attribute isKing. I want to ensure there is exactly one king at a time. It gets tricky when I want to change the king. This requires modification of two documents (to set isKing=true for the new king and isKing=false to the old one).

How do I ensure I won't end up with two or zero kings after some unfortunate concurrent updates?

I was thinking about bulk update, but it doesn't help since it does not support transactions.

Edit: I've seen question Can I do transactions and locks in CouchDB?, but it does not address my case. It also relates to transactions in CouchDB, but that's where similarities end. The problem there is to transactionally read & update one document, while I'm asking about transactional update of two documents. I don't find answers to the other question helpful for my case, but if you think it is duplicate please explain why.

Community
  • 1
  • 1
TMG
  • 2,620
  • 1
  • 17
  • 40
  • Possible duplicate: http://stackoverflow.com/questions/299723/can-i-do-transactions-and-locks-in-couchdb – Chris Snow Apr 07 '15 at 13:52
  • @ChrisSnow - thanks for the comment. I already read the question you mentioned before opening this one. I just didn't find solutions proposed there applicable to my case. The main difference is that I want to update two documents at a time. – TMG Apr 07 '15 at 13:57
  • 1
    Can the state be owned by other document that points to the current king and perhaps a history of kings etc. Or can it be seen as an event that is a document like KingElected and KingAbticated etc... – Daniel Apr 08 '15 at 19:42
  • @Daniel - I liked the idea of isKing flag because it allows to create view with just the kings easily. With other documents keeping record of current king it gets more complex, but anyway, I'll try this approach too. – TMG Apr 09 '15 at 12:36
  • @TMG my feeling is that it's quite common to be checking some field (e.g. `$doctype`) for type of document and then emiting different data. Otherwise I guess you could start trying some two phase commit pattern. – Daniel Apr 09 '15 at 13:07

1 Answers1

3

Transactional Semantics with Bulk Updates

In short, there are none (by design). However, you can ask CouchDB to check that all the documents in your _bulk_docs request pass all your validation functions. If even one fails, none of the documents are written. You can select this mode by including "all_or_nothing":true in your request.

Handle the revision validation in an own validate_doc_update function by comparing oldDoc._rev and newDoc._rev.

If you let fail the validation of one doc - the other will also not be written.

Attention!!! The answer is valid for CouchDB v1 only. CouchDB v2 is ignoring the "all_or_nothing" property.

Community
  • 1
  • 1
Ingo Radatz
  • 1,225
  • 8
  • 9
  • That's interesting. I read about all_or_nothing, but the sentence just after your quote is: "With this mode, if all documents pass validation, then all documents will be updated, even if that introduces a conflict for some or all of the documents." which discouraged me from exploring it. I haven't thought that I could handle the conflict management by myself using the validation you suggest. – TMG Apr 07 '15 at 20:37
  • Are there any limitations or side effects of such validation as compared to the built-in conflict management? – TMG Apr 07 '15 at 20:55
  • IMO no. Your custom revision handling will never executed when the built-jn revision handling mode is not disabled. And even if it would - it simply should be implemented along the built-in equivalent. – Ingo Radatz Apr 08 '15 at 09:57
  • 1
    CouchDB ignores `all_or_nothing` switch starting from v2.x, so I'm going to downvote this answer. – ceremcem Aug 29 '17 at 08:04
  • 1
    @ceremcem Thank you for the correction. I've added your comment to my answer. – Ingo Radatz Jun 15 '18 at 11:28