Saturday, July 18, 2009

Day One: Cleaning up the CouchDB Mess from Day 139

‹prev | My Chain | next›

This is the first post of my second chain. My first lasted 139 days, broken just like (and by) my son's arm (he's OK now). Let's see how long this one can go..

At the end of my last chain, I discovered that I had over-used map/reduce. Over-used it when it was not even necessary.

The problem occurred in the listing of meals by month. I was mapping the meals by the month in which they where made, and then reducing so that all meals in a given month were included in the same result set. I did the reduce wrong, but do not even need map/reduce.

CouchDB views support a startkey and endkey query parameter for extracting a range of keys. If I want all meals from August of 2008, I can supply a startkey of "2008/08/00"—all dates in August are greater than that value (e.g. "2008/08/01" > "2008/08/00"). Similarly, all dates in August are less than "2008/08/99" (September dates are also excluded because "2008/09/01" > "2008/08/99").

Instead expecting to request the by-month reduced view:
      it "should ask CouchDB for meals from year YYYY and month MM" do
RestClient.
should_receive(:get).
with(/key=...2009-05/).
and_return('{"rows": [] }')

get "/meals/2009/05"
end
Now I expect to call the by-date view (non-reduced) with a startkey and endkey:
      it "should ask CouchDB for meals from year YYYY and month MM" do
RestClient.
should_receive(:get).
with(%r{by_date.+startkey=.+2009/05/00.+endkey=.+2009/05/99}).
and_return('{"rows": [] }')

get "/meals/2009/05"
end
Note: the additional match-anything regular expressions account for the quotes that need to surround the JSON formatted values that are required by startkey and endkey.

The resulting code becomes:
get %r{/meals/(\d+)/(\d+)} do |year, month|
url = "#{@@db}/_design/meals/_view/by_date?" +
"startkey=%22#{year}/#{month}/00%22&" +
"endkey=%22#{year}/#{month}/99%22"
data = RestClient.get url
@meals = JSON.parse(data)['rows'].map{|r| r['value']}

@month = "#{year}-#{month}"

url = "#{@@db}/_design/meals/_view/count_by_month?group=true"
data = RestClient.get url
@count_by_year = JSON.parse(data)['rows']

haml :meal_by_month
end
After a few minor fixes to the meals-by-month view spec, I can finally see the meals in August of 2008:



I take a little time to clean up the by-year view in the same way and call it a day.
(commit)

Tomorrow will likely involve some code clean-up. There are probably some CouchDB view no longer being used and the by-year and by-month Sinatra actions are starting to look alike—it may be time to apply some more DRY.

No comments:

Post a Comment