Python SDK 2 Complex/Compound keys

I have a class and I am trying to query a view. My view code looks like this:

function (doc, meta) {
   if(doc.caseid == "000000000000"){
      var result = meta.id.split("-").slice(1,8);
      var year = parseInt(result[0]);
      var month = parseInt(result[1]);
      var day = parseInt(result[2]);
      var hour = parseInt(result[3]);
      var minute = parseInt(result[4]);
      var seconds = parseInt(result[5]);
      var mili = parseInt(result[6]);
     emit([year,month,day,hour,minute,seconds,mili], doc);
  }
}

My cherrypy server code looks like this:

class HelloWorld:
@cherrypy.expose
def index(self):
	if 'count' not in cherrypy.session:
		cherrypy.session['count']=0
	cherrypy.session['count'] +=1
	
	cb = Bucket(connection_string, password=passwd)
	q = Query()
	q.limit = 5 # Limit to 5 results
	q.mapkey_range = ([2015,1,None,None,None,None,None],     [2015,12,None,None,None,None,None])
	rows = cb.query('_design//tt ', 'tracetest', query=q)
	out =""
	try:
		for row in rows:
			out += row
	except CouchbaseError as e:
		if e.is_data and isintance(e, NotFoundError):
		# handle not found
			pass
		elif e.is_network:
			return "Got network error"
		elif e.is_data:
			return "Got other data-related error"
		else:
			ekey = " key : "
			if e.key:
				ekey += key
			else:
				ekey += " N/A"
			return "Got unhandled error code"+ekey
		
	n = "Hello world! %s" % (cherrypy.session['count'],)
	return out

I am trying to get at a view called _design//tt/view/tracetest
Am I referencing this correctly? Is this the right way to do a compound key query?

My url looks like http://localhost:8092/telemetry-trace/design/dev%2Ftt/_view/tracetest?stale=false&inclusive_end=false&connection_timeout=60000&limit=10&skip=10

{"total_rows":59,"rows":[
    {"id":"39CEED3C8145F1848AF0C7F76C34596A-2015-3-2-15-16-51-653000000",......
]
}

Show results looks like this

Key                                                          Value

[2015,2,25,16,19,8,47000000]
39CED3B5B88FD6232EE65E918A356C53-2015-2-25-16-19-8-47000000  ....  {<Some Doc data>}

On the cherrypy server I get the following output

Got unhandled error code key : N/A

I have verified that server can do a get(someid), so I know its connected properly. I think my problem here is referencing the view.

Again, what I would like to know is am I referencing this correctly? Is this the right way to do a compound key query?

the _design/ and _view parts of the query URL are just internal forms. To actually query a view in the SDK, just pass tt as the design, not _design/tt.

Also, you probably want to print out e as well :slight_smile:

1 Like

That is actually harder than it sounds

 500 Internal Server Error

The server encountered an unexpected condition which prevented it from fulfilling the request.

Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\cherrypy\_cprequest.py", line 670, in respond
    response.body = self.handler()
  File "C:\Python27\lib\site-packages\cherrypy\lib\encoding.py", line 217, in __call__
    self.body = self.oldhandler(*args, **kwargs)
  File "C:\Python27\lib\site-packages\cherrypy\_cpdispatch.py", line 61, in __call__
    return self.callable(*self.args, **self.kwargs)
  File "C:\Users\home\Repositories\telemetry\telemetrydashboard.py", line 45, in index
return "Got unhandled error code"+ekey + " " + e
TypeError: cannot concatenate 'str' and 'HTTPError' objects

I am actually running cherrypy in a windows service. I get an HTTPError, but my bucket object definitely connects.

def basictest(self):
	cb = Bucket(connection_string, password=passwd)
	result = cb.get('39CED3B5B88FD6232EE65E918A356C53-2015-2-25-16-19-8-47000000')
	return result.value

This works and gives me back information from the result

The HTTPError is due to getting a negative reply from the view query. This means the client was able to connect to the view service, but for some reason, the server did not like your query. You should print the query in a separate line (Python will complain if you try to concatenate a string and an exception object, so just print them individually).

To help debugging, you can also display the encoded version of your query (http://pythonhosted.org/couchbase/api/views.html#couchbase.views.params.Query.encoded). This will show you the query parameters as they are going to be sent to the server, and can help in debugging why your query went wrong.

1 Like

Here is the result
startkey=%5B2015%2C%201%2C%20null%2C%20null%2C%20null%2C%20null%2C%20null%5D&endkey=%5B2015%2C%2012%2C%20null%2C%20null%2C%20null%2C%20null%2C%20null%5D&limit=5

So I copied that and went to the view in the server

http://localhost:8092/telemetry-trace/_design/%2Ftt/_view/tracetest?startkey=%5B2015%2C%201%2C%20null%2C%20null%2C%20null%2C%20null%2C%20null%5D&endkey=%5B2015%2C%2012%2C%20null%2C%20null%2C%20null%2C%20null%2C%20null%5D&limit=5

That works, so probably there is something still wrong with the connection here.

Thanks that was very helpful. We are really narrowing this down.

Ok, I made progress

500 Internal Server Error

The server encountered an unexpected condition which prevented it from fulfilling the request.

Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\cherrypy\_cprequest.py", line 670, in respond
    response.body = self.handler()
  File "C:\Python27\lib\site-packages\cherrypy\lib\encoding.py", line 217, in __call__
self.body = self.oldhandler(*args, **kwargs)
  File "C:\Python27\lib\site-packages\cherrypy\_cpdispatch.py", line 61, in __call__
return self.callable(*self.args, **self.kwargs)
  File "C:\Users\Repositories\telemetry\telemetrydashboard.py", line 30, in index
out += row
TypeError: cannot concatenate 'str' and 'ViewRow' objects

So I think the issue was the designer injected a %2F (or a slash) into the tt name. I don’t know why.

As a result

rows = cb.query('%2Ftt','tracetest', query=q)

Now gives me a different error.

Anyhow, now that I have ViewRows, is there a quick way to dump them as raw json?

Thanks so much for the help.

You should be able to just print the row object, if all you want to do is debug it.

The row is parsed out from its JSON form very early on, so there is no quick way. There’s always something like:

out += json.dumps({'key': row.key, 'value': row.value, 'id': row.docid})
1 Like

Another related matter of interest

When do I need to use

+q.STRING_RANGE_END

Is it only with strings? Is it required in a compound key of strings? Does it get tacked onto the end of every string in the compound end key?

Thanks again.

Adding JSON dumps does the trick, I now have output. Thanks a lot! :relieved:

You need to use STRING_RANGE_END to specify the upper range of a search. This is the semantical equivalent of saying:

mapkey_range(["United States", "A"], ["United States", "Z"])

and your emit looks something like this:

emit([doc.country, doc.state])

In this case, the logical query is “Give me anything in the United States”.
However, views has the following caveats:

  • If you specify mapkey_range(["United States", null], ["United States, null]) then you would only get those entries which don’t have a state. This is because the end range for the second “column” is set to anything matching between null and null. Obviously "NV" does not fall into this category!

  • If you specify mapkey_range(["United States, "A"], ["United States", "Z"]), then only entries which have a state would be considered, since null is not between "A" and "Z". Also, depending on the kind of data you have, you might end up with non-ASCII characters which would sort higher than "Z".

STRING_RANGE_END is logically the wildcard character (think *). It’s actually a very high unicode character, so it’s guaranteed that any character will sort lower than it, making it suitable for an end-range

See also https://wiki.apache.org/couchdb/View_collation (Note, Couchbase is not CouchDB; they are different projects, and other than a common historical ancestry, are not related. Nevertheless views functions similar to this).

1 Like

Thanks so much, excellent answers