1

I am storing some locale based data in the following format in the CouchDB.

{
  "_id": "a62f81b5afad1857c2f6399db500c73b",
  "_rev": "3-923e5ed468e0f617f09057035b41051a",
  "type": "CAT",
  "origin_id": "1",
  "locale": "ar",
  "values_translation": {
    "id": "ar",
    "title": ""
  }
}

I use Nano as the client in Node JS app and I need to insert if not exists / update if exists docs using the Update Handler. for that I have created the following document in the couchDB;

  "_id": "_design/handler",
  "_rev": "36-d2d08a0a822a762ac07faa4042eca5a0",
  "updates": {
    "handler": "function(doc, req){ 
       if (doc.type === req.type && doc.origin_id === req.origin_id && doc.locale === req.locale)
       { return [doc, 'OK'];}
       else { return [null, 'KO']; }
    }"
  },
  "language": "javascript"
}

But When I run it using the following Nano Method,

translationsDB.atomic("handler", "handler", "_design/handler",
      { type, origin_id, locale, values_translation: value }).then((response) => {
        console.log(response);
      }).catch(err => {
        console.log(err);
      });

it always returns 'OK' even if I pass invalid data. For real data it returns OK but it does not update the document. Need to figure how to achieve this (update if the doc is existing or insert if it is a new doc) in right way.

mapmalith
  • 1,303
  • 21
  • 38
  • 2
    Your handler method doesn't return a new structure (new document) ever, only an existing one, that doesn't quite look right. Here's a pointer to the CouchDB doc on update handlers, maybe that helps: https://docs.couchdb.org/en/stable/ddocs/ddocs.html?highlight=update%20handler#update-functions – chrisinmtown Aug 13 '19 at 12:30

1 Answers1

2

current code's behavior

Your custom field names like locale are undefined for both doc and req, since:

  1. doc.customfield, atomic("handler", "handler", "_design/handler" is calling the design on the design doc itself (3rd parameter to atomic is the document to update) and your design doc naturally lacks customfields you put on your example locale document.

  2. req.customfield, these are non-existent req fields, fields passed in by atomic are in JSON in req.body as shown in the atomic docs.

So your checks always pass for these fields, given undefined === undefined is true.

Then:

  1. you update the design doc without ever modifying doc:
{ return [doc, 'OK'];}

so couchdb saves the unchanged design doc (problem 1), causing only its _rev to keep going up:

{ "_id": "_design/handler", "_rev": "36-...

but it is the wrong document and no fields are being changed.

To fix these 3 problems

  1. Call it on the correct document:

    translationsDB.atomic("handler", "handler", "a62f81b5afad1857c2f6399db500c73b",

  2. Extract the customfields from req.body:

       var reqb = JSON.parse(req.body); 
       if (doc.type === reqb.type && doc.origin_id === reqb.origin_id && doc.locale === reqb.locale)
    
  3. Make some modification to the document being returned:

      { return [Object.assign({}, doc, reqb), 'OK'];}    
    
lossleader
  • 13,182
  • 2
  • 31
  • 45
  • Thanks for this nice explanation and according to your fix we need pass the `id` - `a62f81b5afad1857c2f6399db500c73b` and in that case, I will need to get the DOC querying the DB, but one of major reason I use the Update Handler is to update or insert the doc without querying DB to increase the performance. Is there a way to achieve this without passing the docID itself? – mapmalith Aug 15 '19 at 04:31
  • 1
    @mapmalith not really, updatefun gets the 1 `doc` based on the id passed if it exists or no doc.. since updating a doc requires its rev, it can therefore update the 1 doc it may have found with a client provided id or create any new doc with a new id. The way to avoid a query is not to use random ids and instead determine unique ids from by building a lookup key from doc contents such that you know if the doc with an id exists its needs to be updated and if it doesn't exist it is safe to create. I.e. your ids would be set at creation as ${type}-${origin_id}-${locale}. – lossleader Aug 15 '19 at 17:35