More CouchDB Fun...
Written by
on
in
Snaking.
Continuing to work on my little project. Mostly messing about with UI and getting CouchDB to do what I want it to do. The query mechanism is a little weird when you're used to SQL(Alchemy) and complex referential schemas. For instance, say you want to be able to total votes across M objects with N users able to vote up/down (once) for any given object (and you want to be able to restrict the search to a single query).
{ 'type': 'vote', 'survey':'surveyname', 'target': targetid, 'vote': -1 }
The map function is pretty straightforward, you extract the keys you want to query against with the vote-value like so:
function (doc) { if (doc.type == 'vote') { emit( [doc.survey,doc.target], doc.vote ); } }
The reduce function is where it gets interesting. CouchDB will potentially *rereduce* your partially reduced values, so you need to be able to handle both direct summing/counting and summing partial values in your reduce function:
function (keys,values,rereduce) { var sum = 0; var count = 0; values.forEach( function( v ) { if (rereduce) { sum = sum + v.sum; count = count + v.count; } else { sum = sum + v; count = count + 1; } } ); return {sum:sum,count:count}; }
Works reasonably well, but I'm still finding myself wanting to do "joins" so that I can retrieve the vote counts when I retrieve the "target" objects. Haven't found the equivalent of that for CouchDB yet.
Comments
Comments are closed.
Pingbacks
Pingbacks are closed.
Jan Lehnardt on 01/09/2010 6:44 a.m. #
Hey,
Check out: http://www.cmlenz.net/archives/2007/10/couchdb-joins
Cheers
Jan
--
Mike C. Fletcher on 01/09/2010 12:26 p.m. #
Thanks for the pointer. That blog-post appears to have already been integrated into the wiki, and I followed that. Problem is here we're discussing a *view* joined against a query. That is, I want to get the comment *counts* without loading the comments (this comment-count is a recursive value, so viewing the front-page would cause every document in the system to be counted).
Similarly, I want to be able to limit the counts of comments based on properties of the documents involved.
The use of the "keys" field in the query allows for fairly good "two-request" joins, where you do the filtering of one document set, extract the ids, then query a view for the corresponding (composed) keys, but you wind up writing a lot of logic that is "automatic" in an SQL system. (I actually consider the view-collation hack to be a similarly non-automatic (and non-obvious) trick; I wouldn't want to pass that off to a client's junior programmers to maintain without a boatload of docs).
In SQLAlchemy I will often build joined queries across a dozen normalized tables with filter criteria on 4 or 5 of the tables and complex collation/grouping operations on the results. You'd really want an abstraction mechanism above CouchDB to start doing that kind of stuff.