0

Is it possible to put or bulkDocs into couchdb/pouchdb and get the same behaviour as in replication, i.e. winning revision with _conflicts instead of a 409 response?

Basically I would like to avoid the conflict case in the following code:

  const docs = Object
    .keys(pendingSet)
    .map(id => toDoc(deepClone(pendingSet[id]), { id, rev: this.revCache.get(id) }))

  const results = await this.db.bulkDocs(docs)
  const conflicts = []

  for (let n = 0; n < results.length; ++n) {
    const result = results[n]
    if (result.error === 'conflict') {
      // TODO: This needs review...
      const doc = await this.db.get(docs[n]._id)
      const rev = `${doc._rev.split('-')[0]}-${this.serverName}`
      conflicts.push({
        ...docs[n],
        _rev: rev
      })
      this.revCache.set(doc._id, rev)
    } else if (result.error) {
      callback(result.error)
    } else {
      this.revCache.set(result.id, result.rev)
    }
  }

  await this.db.bulkDocs(conflicts, { new_edits: false })

I've gotten a bit of a hint from pouchdb but I'm still unsure how to apply it.

EDIT1: Updated with latest code.

ronag
  • 49,529
  • 25
  • 126
  • 221

2 Answers2

1

CouchDB tries to protect itself from conflicts, so if you try and modify a revision of a document that CouchDB 'knows' that has already been superseded, you will get a 409 response.

The way replication "gets away with it" is because documents are bulk written to the target machine with the flag "new_edits=false". This instructs CouchDB not to police the revision tokens, but to accept the incoming one (writes coming from a replication source already have their own revision trees).

You can do this yourself with calls like this:

ccurl -X POST -d '{"docs":[{"_id":"x","_rev":"1-myrevtoken","y":3}],"new_edits":false}' '/a/_bulk_docs'

In this case I have forced a second "revision 1" into a document that already had a "revision 2":

id = x
├─ 1
│  ├─ 1-myrevtoken
│  └─ 1-a6664c0114e6002415a47b18d4c9d32f
└─ 2-bca8f049e40b76dbfca560e132aa5c31 *

The winner is still "revision 2" but the conflict on revision 1 remains unresolved, until you decide to resolve it.

Glynn Bird
  • 5,507
  • 2
  • 12
  • 21
  • Thanks! That helped me in the right direct. A question though. How is the new "myrevtoken" generated? Is it a constant uuid for the application? – ronag Oct 14 '16 at 16:43
  • Usually a revision token is a hash of the content of the document. But it's up to you. – Glynn Bird Oct 15 '16 at 10:04
  • Typo - should be `new_edits=false` (not `true`) in your second paragraph. – Rob Hogan Aug 06 '18 at 06:27
0

With CouchDB you can set all_or_nothing: true in a _bulk_docs request. This creates new revisions regardless of conflicts. With new_edits: false you don't get a new revision which makes sense for replication but maybe not if you are actually submitting an update of the document. PouchDB doesn't have an all_or_nothing option on its bulkDocs.

Ian
  • 2,078
  • 2
  • 19
  • 19