Does updating a design document in couchdb cause rebuilding of views?

Akshat Jiwan Sharma, Sat Oct 18 2014

The opinions are a bit divided on this question. Some people say "yes every time you update a design document couchdb rebuilds the views" while others claim "no views are rebuild only when the map/reduce part of the design document changes". Couchdb's wiki seems to support the first claim

To change a view or multiple view just alter the design document (see HttpDocumentApi) they are stored in and save it as a new revision. This causes all the views in that design document to be rebuilt on the next access in case the view code has been changed.

But we will test just to make sure. Couchdb provides us with /{db}/_design/{ddoc}/_info api that

"Obtains information about the specified design document, including the index, index size and current status of the design document and associated index information."

It should be fairly easy to test the two claims regarding views and design document updation. We will use this as our test design document:-

{
   "_id": "_design/test",
   "_rev": "1-d294ec6c760dbfb53a2cac08ac7e43c1",
   "language": "javascript",
   "views": {
       "test_updation": {
           "map": "function(doc) {\nif(doc.roll_no)  emit(doc.roll_no,null);\n}"
       }
   }
}

Let's query the info endpoint:-

curl http://localhost:5984/test_d_doc/_design/test/_info

{
  name: "test",
  view_index: {
    signature: "9e0e76f6b262896317b8a7c3d1c533bd",
    language: "javascript",
    disk_size: 4188,
    data_size: 193,
    update_seq: 3,
    purge_seq: 0,
    updater_running: false,
    compact_running: false,
    waiting_commit: false,
    waiting_clients: 0
  }
}

Make a note of the signature field that we will be using for comparison. First let us update a design document by say adding a show function? Our new design document looks like:-

{
  _id: "_design/test",
  _rev: "2-2bb1be47ebed5d6f43699f0c83b79d91",
  language: "javascript",
  views: { test_updation: { map: "function(doc) {\nif(doc.roll_no)  emit(doc.roll_no,null);\n}" } },
  shows: { some_show: "function(doc,req){\n    return \"hello world\";\n}" },
  couchapp: {
    signatures: { },
    objects: { },
    manifest: [
      "language",
      "shows/",
      "shows/some_show.js",
      "views/",
      "views/test_updation/",
      "views/test_updation/map.js"
    ]
  }
}

Now let us check if there is any change in the signature of the the view index

curl http://localhost:5984/test_d_doc/_design/test/_info

{
  name: "test",
  view_index: {
    signature: "9e0e76f6b262896317b8a7c3d1c533bd",
    language: "javascript",
    disk_size: 4188,
    data_size: 193,
    update_seq: 3,
    purge_seq: 0,
    updater_running: false,
    compact_running: false,
    waiting_commit: false,
    waiting_clients: 0
  }
}

Nope. As you can see the view signature for the updated design document is exactly the same as the signature before. Let's also check the database directory and the view files that are stored in it. My database dir is at /usr/local/var/lib/couchdb and the view which we are testing is stored in /usr/local/var/lib/couchdb/.test_d_doc_design/mrview/ and sure enough there is a view file named 9e0e76f6b262896317b8a7c3d1c533bd.view

Okay let's see what happens when we change the view function. Here is what our design document looks now

{
  _id: "_design/test",
  _rev: "3-e50012d5a2ad7ff96fc4da950175b292",
  language: "javascript",
  views: { test_updation: { map: "function(doc) {\nif(doc.roll_no)  emit(doc.roll_no,doc);\n}" } },
  shows: { some_show: "function(doc,req){\n    return \"hello world\";\n}" },
  couchapp: {
    signatures: { },
    objects: { },
    manifest: [
      "language",
      "shows/",
      "shows/some_show.js",
      "views/",
      "views/test_updation/",
      "views/test_updation/map.js"
    ]
  }
}

Notice the change in the view function. Now we are emitting a doc instead of emitting a null field like we were before

and the info:-

{
  name: "test",
  view_index: {
    signature: "ef12fccd479fa831d87abb63b023844b",
    language: "javascript",
    disk_size: 51,
    data_size: 0,
    update_seq: 0,
    purge_seq: 0,
    updater_running: false,
    compact_running: false,
    waiting_commit: false,
    waiting_clients: 0
  }
}

Aha! the signature has changed. Now lets checkout the view files in the directory..... and voila! as expected we have have a ef12fccd479fa831d87abb63b023844b.view in the database directory.

Conclusion

The map reduce views are stored in the a file which is named after the md5 hash of the content of all the views in the design document. An index rebuild occurs only if the content of the view changes. A change in the content of design document has no effect on the view rebuilding.

But wait! what happens if there are multiple views in a couchdb design document?

There are two important things to understand here:-

  1. The map reduce views of a design document (it does not matter if there is only one or many) is stored in a file that is named after the md5 hash of content of the views.
  2. If the content of any one of the views in the design document changes the md5 hash will change and couchdb will have to create a new index file.

Based on the observations that we made above it is easy to conclude that if there are multiple views in couchdb and any one of them changes couchdb will recalculate the index again. Because all the views of a design document are stored in a single file and that file is named after the hash of it's contents. Consequently if content changes the name of the file changes and recalculation is triggered.

So hopefully this will clear some confusion regarding couchdb views and design documents. If you liked this article you will also like caching in couchdb, easy user accounts management in couchdb and the official couchdb blog

Until next time :)


comments powered by Disqus