Saturday, May 9, 2009

Prototyping CouchDB Views

‹prev | My Chain | next›

With recipe search done (yay!), I am ready to move on to other things today. There are only a few scenarios left, all dealing with the meal in which the recipes were originally served.

Before moving onto those things, I thought I would play around with CouchDB views a bit first. It's somewhat amazing to me that I have spent this much time on a CouchDB project and have yet to do something as basic as a view.

Ah well, time to rectify that oversight.

On our current site, we have a list of recipes by ingredient:



It would be very nice to be able to reproduce that with a CouchDB view.

In Javascript, what I would like do with each recipe document is this:
function (doc) {
for (var i in doc['preparations']) {
var ingredient = doc['preparations'][i]['ingredient']['name'];
var value = [doc['_id'], doc['title']];
emit(ingredient, value);
}
}
For each recipe document, iterate over each ingredient preparation and emit the ingredient, pointing to the document title and ID (enough to link to the recipe). I add this to the DB using futon. From the main DB page, I select the Design Document view from the drop-down and create the following document:



Accessing the view results in:
cstrom@jaynestown:~/repos/eee-code$ curl "http://localhost:5984/eee/_design/recipes/_view/by_ingredients"
{"total_rows":72,"offset":0,"rows":[
{"id":"2008-07-21-spinach","key":"artichoke hearts","value":["2008-07-21-spinach","Spinach and Artichoke Pie"]},
{"id":"2008-07-19-oatmeal","key":"barley","value":["2008-07-19-oatmeal","Multi-grain Oatmeal"]},
{"id":"2006-10-08-dressing","key":"black pepper","value":["2006-10-08-dressing","Mustard Vinaigrette"]},
{"id":"2008-07-19-oatmeal","key":"brown sugar","value":["2008-07-19-oatmeal","Multi-grain Oatmeal"]},
{"id":"2002-01-13-hollandaise_sauce","key":"butter","value":["2002-01-13-hollandaise_sauce","Hollandaise Sauce"]},
{"id":"2006-07-26-fish","key":"butter","value":["2006-07-26-fish","Pan-Fried Fish with Potato Crust"]},
{"id":"2006-06-17-shrimp","key":"cardamom pod","value":["2006-06-17-shrimp","Curried Shrimp"]},
{"id":"2007-01-15-soup","key":"celery","value":["2007-01-15-soup","Crockpot Lentil Andouille Soup"]},
{"id":"2006-06-17-fish","key":"cilantro","value":["2006-06-17-fish","Green Chutney Covered Fish"]},
{"id":"2006-06-17-raita","key":"cilantro","value":["2006-06-17-raita","Yogurt Raita"]},
{"id":"2006-06-17-shrimp","key":"cinnamon","value":["2006-06-17-shrimp","Curried Shrimp"]},
{"id":"2008-07-19-oatmeal","key":"cinnamon","value":["2008-07-19-oatmeal","Multi-grain Oatmeal"]},
{"id":"2006-06-17-shrimp","key":"clove","value":["2006-06-17-shrimp","Curried Shrimp"]},
{"id":"2006-06-17-raita","key":"cucumber","value":["2006-06-17-raita","Yogurt Raita"]},
{"id":"2006-06-17-raita","key":"cumin","value":["2006-06-17-raita","Yogurt Raita"]},
{"id":"2006-06-17-shrimp","key":"curry leaves","value":["2006-06-17-shrimp","Curried Shrimp"]},
{"id":"2008-07-19-oatmeal","key":"dry milk powder","value":["2008-07-19-oatmeal","Multi-grain Oatmeal"]},
{"id":"2002-01-13-hollandaise_sauce","key":"egg yolks","value":["2002-01-13-hollandaise_sauce","Hollandaise Sauce"]},
{"id":"2002-01-13-eggs_benedict","key":"eggs","value":["2002-01-13-eggs_benedict","Crab Eggs Benedict"]},
{"id":"2008-07-21-spinach","key":"eggs","value":["2008-07-21-spinach","Spinach and Artichoke Pie"]},
...
They are sorted by ingredient name, but there are multiple records with "cinnamon" and with "eggs". What I really want is a list of each ingredient pointing to the recipes in which they are used. Sure I could assemble that list in Ruby code (especially with the nice ordering above), but maybe CouchDB can help?

Of course it can!

In addition to the "map" attribute for "by_ingredients", I add the following, as-simple-as-it-gets "reduce" attribute:
function(keys, values, rereduce) {
return values;
}
In Futuon, this looks like:



Now when I access the by_ingredients view, this time with the group attribute set, I get exactly what I am looking for:
cstrom@jaynestown:~/repos/eee-code$ curl "http://localhost:5984/eee/_design/recipes/_view/by_ingredients?group=true"
{"rows":[
{"key":"artichoke hearts","value":[["2008-07-21-spinach","Spinach and Artichoke Pie"]]},
{"key":"barley","value":[["2008-07-19-oatmeal","Multi-grain Oatmeal"]]},
{"key":"black pepper","value":[["2006-10-08-dressing","Mustard Vinaigrette"]]},
{"key":"brown sugar","value":[["2008-07-19-oatmeal","Multi-grain Oatmeal"]]},
{"key":"butter","value":[["2006-07-26-fish","Pan-Fried Fish with Potato Crust"],["2002-01-13-hollandaise_sauce","Hollandaise Sauce"]]},
{"key":"cardamom pod","value":[["2006-06-17-shrimp","Curried Shrimp"]]},
{"key":"celery","value":[["2007-01-15-soup","Crockpot Lentil Andouille Soup"]]},
{"key":"cilantro","value":[["2006-06-17-raita","Yogurt Raita"],["2006-06-17-fish","Green Chutney Covered Fish"]]},
{"key":"cinnamon","value":[["2008-07-19-oatmeal","Multi-grain Oatmeal"],["2006-06-17-shrimp","Curried Shrimp"]]},
{"key":"clove","value":[["2006-06-17-shrimp","Curried Shrimp"]]},
{"key":"cucumber","value":[["2006-06-17-raita","Yogurt Raita"]]},
{"key":"cumin","value":[["2006-06-17-raita","Yogurt Raita"]]},
{"key":"curry leaves","value":[["2006-06-17-shrimp","Curried Shrimp"]]},
{"key":"dry milk powder","value":[["2008-07-19-oatmeal","Multi-grain Oatmeal"]]},
{"key":"egg yolks","value":[["2002-01-13-hollandaise_sauce","Hollandaise Sauce"]]},
{"key":"eggs","value":[["2008-07-21-spinach","Spinach and Artichoke Pie"],["2002-01-13-eggs_benedict","Crab Eggs Benedict"]]},
...

No comments:

Post a Comment