Making today worse so tomorrow seems better.

Getting a Good View of Your Couch

on

So far I have been doing all my CouchDB queries using “temporary views” which are Javascript strings which are POSTed to the database and used to select the records you’re interested in. A more efficient way to do it is to save the Javascript strings as documents, these can be called with less traffic and a simpler API. “Permanent views” also create cached indexes, so they offer performance advantages over temporary views as well.

Tim Kofol took my ideas and ran with them, creating an ingenious way to maintain CouchDB views right in the Ruby code. Witness:

class Post < Blarg::CouchBase 
  couch_accessor :tags

  couch_view :comments_view, %[
    function(doc) {
      if (doc.type  "Comment") {
        map(doc.post_id, doc);
      }
    }
  ]

  couch_view :all_tags_view, %[
    function(doc) {
      if (doc.type  ‘Post’) {
        map(null, doc.tags);
      }
    }
  ]

  def self.all_tags   
    self.all_tags_view.flatten.uniq.sort
  end

  def comments
    comments = self.class.comments_view(:key => self.document_id)
    comments.sort{|a,b| a.created_at <=> b.created_at}
  end
end

With the views relevant to this class defined in the class itself, we need to load them into CouchDB. I added Rake task which finds all views defined in the project and loads them into CouchDB, creating them or replacing older versions.

rake db:views:load

It’s conceptually a little bit like doing rake db:migrate with ActiveRecord.

Unfortunately CouchDB so far only provides the “map” part of MapReduce, so I still need Post.all_tags and Post#comments to take care of the “reduce” part. When full MapReduce functionality is ready in CouchDB, it will be great to define all the logic in the views and be able to dispense with the silly little helper methods.

One thing that bugs me is that views themselves are just Javascript strings. CouchObject itself has a plugin for CouchDB allowing it to use Ruby as a query language, but I didn’t have any luck getting it to work. It would be pretty fantastic to be able to define views like regular Ruby methods (with some syntactic sugar) and load them up with this interface.

Even better would be a generic query interface, maybe something like Squirrel that could be parsed into a CouchDB view. An exciting possibility of this approach is that you could parse the same query code to talk to other Document Oriented Databases, such as ThruDB SimpleDB or RDDB .