couchdbpouchdb

CouchDB/PouchDB design documents query with startkey endkey not working


In my database I have (not only) two types of documents in a one-to-many relationship. I tried to manage this like the following example shows:

{ 
  _id : "class:xyz"
  type: "class"
  ... other keys ...
}

{
  _id : "class:xyz:pupil:abc"
  type: "pupil"
  ... other keys ...
}

If I query my docs with allDocs() like

http://url_of_my_server:5984/my_database/_all_docs?include_docs=true&?startkey="class:xyz:pupil:"&endkey="class:xyz:pupil:\ufff0"

I get all docs of type pupil related to the mentioned doc of type class like wanted.

For performance I had the idea to introduce a design document to query only the docs of type pupil and not all docs every time:

{
  "_id": "_design/types",
  "language": "javascript",
  "views": {
    "classes": {
      "map": "function(doc){ if(doc.type == \"class\"){emit(doc.id, doc);} }"
    },
    "pupils": {
      "map": "function(doc){ if(doc.type == \"pupil\"){emit(doc.id, doc);} }"
    },
  }
}

But if I query with this design document like

http://url_of_my_server:5984/my_database/_design/types/_view/pupils?include_docs=true&?startkey="class:xyz:pupil:"&endkey="class:xyz:pupil:\ufff0"

I get no result (only an empty array/no rows).

Where is my mistake or what is wrong in my conception? I actually have no idea? Thanks in advance for your advice.


Solution

  • First, for a view never emit the document as a value; it is quite redundant since one may use include_docs=true - and worse, it consumes storage unnecessarily.

    Assuming two documents

    {
      _id : "class:xyz:pupil:abc"
      type: "pupil"  
    },
    {
      _id : "class:xyz:pupil:xyz"
      type: "pupil"  
    }
    

    And the map function for pupils

    "pupils": {
      "map": "function(doc){ if(doc.type == \"pupil\"){emit(doc.id, doc);} }"
    }
    

    The view index for pupils looks like this

    id key value
    class:xyz:pupil:abc null {"_id": "class:xyz:pupil:abc", /* etc */ }
    class:xyz:pupil:xyz null {"_id": "class:xyz:pupil:xyz", /* etc */ }

    So the key columns are null because the map function is emitting doc.id as the key.

    See it? doc.id is undefined - emit(doc._id) instead.

    Fix the design document map functions (including not emitting doc as value)

    {
      "_id": "_design/types",   
      "views": {
        "classes": {
          "map": "function(doc){ if(doc.type == \"class\"){emit(doc._id);} }"
        },
        "pupils": {
          "map": "function(doc){ if(doc.type == \"pupil\"){emit(doc._id);} }"
        }
      }
    }
    

    Given the two hypothetical documents, the pupils index now looks like this

    id key value
    class:xyz:pupil:abc class:xyz:pupil:abc null
    class:xyz:pupil:xyz class:xyz:pupil:abc null

    Now that the view index's key has a value the query will operate as intended.

    I highly recommend using Fauxton as it provides a quick means to view an index among other things.