Querying views with compound keys in couchbase-lite


#1

I’m having an issue querying a view that as a compound key (of 2 items). The url I am constructing is returning the entire view, but what I want is a subset of that view. From the docs I understand that I need to specify a startKey and endKey as url parameters.

Its seems that the startKey should be an array of just 1 item.

The endKey should be an array of 2 items, the 1st being the same as my startKey and the 2nd being an empty object {}. Correct?

So I now have json arrays in my url as parameters. Should they be url encoded? It doesn’t seem to matter if I do or don’t, I still get the full view back. Is a ‘GET’ the wrong method?

I guess my question is this: how do I construct an http request to query a view with a compound key?


#2

Can you post some sample source for your view (map function) and how you are querying it?

Btw some docs on querying compound keys are here:

http://developer.couchbase.com/documentation/mobile/1.1.0/develop/guides/couchbase-lite/native-api/query/index.html

Second is the handling of compound (array) keys. When a view’s keys are arrays, it’s very common to want to query all the rows that have a specific value (or value range) for the first element. The start key is just a one-element array with that value in it, but it’s not obvious what the end key should be. What works is an array that’s like the starting key but with a second object appended that’s greater than any possible value. For example, if the start key is (in JSON) [“red”] then the end key could be [“red”, “ZZZZ”] … because none of the possible second items could be greater than “ZZZZ”, right? Unfortunately this has obvious problems. The correct stop value to use turns out to be an empty object/dictionary, {}, making the end key [“red”, {}]. This works because the sort order in views puts dictionaries last.


#3

Thanks for the reply. I’ve read the docs extensively but can’t find instructions on how to construct an http request that queries a view with a compound key.

My map function looks something like this:

    function (doc) {
       emit([doc.group_id, doc.client_timestamp], doc);
    }

And I’ve tried various ways of querying the view. Such as:

http://localhost:5984/myapp/_design/myapp/_view/my_view_name?startkey=["some_id"]&endkey=["some_id",{}]

This doesn’t work. I assume because its not a valid URL (the query string parameters aren’t encoded correctly). So if I encode them (using encodeURIComponent()) I end up with this:

http://localhost:5984/myapp/_design/myapp/_view/my_view_name?startkey=%5B%22some_id%22%5D&endkey=%5B%22some_id%22%2C%7B%7D%5D

Which doesn’t work either. Maybe the encoding is wrong? Just one working example would help. I’ve looked at the java code that I supposed to decode these parameters but can’t figure out quite what the url is supposed to look like (both startled and end key get parsed into Object.class).

Could you supply a url that would work for the example in the docs that you posted? Or point me to any one example of it working. I’m completely stuck!

Any advice would be greatly appreciated.


#4

Hi, I’ve got it working. The second form of URL was correct (with the http-encoded json arrays). There was a bug in the react-native-couchbase-lite API that was breaking the IOS http stack somehow. I’ll try and get it fixed.

An example query would have still been useful though, I couldn’t find any in the docs.


#5

@nick-couchbase can you explain how you got that working. I am having the same problem. My view is:

map : function(doc) {
	if (doc.type == "Contact" && doc.party && doc.contacPurpose) {
		emit([doc.party, doc.contacPurpose],doc)
	}
}

then I do this request:

http://dd96c741-d105-4c7a-b410-d3e4c3ab11c4:b9ea28b8-6168-4165-9be0-da82ae53c161@localhost:5985/todos/_design/todo/_view/ContactsByPurpose?startkey="126490"&endkey="BILLING_LOCATION"

I get 0 results even though I have the document in the database:

{
  "offset": 0,
  "total_rows": 24,
  "rows": []
}

#6

This is the correct url that fixed my issue:

http://0e8ce535-0e98-4a81-86c2-341514743d7b:d9de1753-1b78-4939-a31e-c00c43bf2b8f@localhost:5984/todos/_design/todo/_view/ContactsByPurpose?key=["126490",+"BILLING_LOCATION"]

I used the ng-couchbase-lite angular wrapper:

var key = ‘[“126490”, “BILLING_LOCATION”]’;
hossDatabase.queryView(config.designDoc,“ContactsByPurpose”,{ key: key }).then(function(res){
console.log(JSON.stringify(res,null,2));
});