Doing Cool Stuff w/ CouchDB January 6th, 2009
I've been looking for an excuse to use CouchDB for something for quite a while now. There's been lots of controversy around it and it's only getting louder the more popular/mainstream the project gets.
One of the biggest points for/against CouchDB is that it definitely is not a replacement to a regular RDBMS (like MySQL) that we're all used to. For in the sense that sometimes MySQL is overkill. Against in the sense that it's got a tiny fraction of MySQL's features.
Nichey vs Overkill
The problem is that CouchDB seems, to me, to have a very specific niche. It took me forever to find a project that it would be better at than something 'normal' like MySQL. Finally, I decided to add a 'ratings' feature to this blog, not an uncommon thing, using CouchDB.
This entire site (except for a few small parts, stay tuned for future posts!) is pre-generated by a system not unlike (but quite a bit more elaborate than) what I discussed in Doing Cool Stuff w/ CouchDB. Now, if you ask me, it would be crazy to install MySQL (or whatever), setup a Rails app or something and integrating my static content into it somehow (either in the new db or...), blah, blah, blah — just to get a rating system.
Back-end w/ CouchDB
First I needed to setup/install CouchDB. Easy enough on my Ubuntu server. Then I created a database with a design document that looks like this:
So, documents (our ratings) can be in any form that includes a
permalink attribute, a
rating attribute and
type attribute with a value of "rating" (we could use other
types in the future for other, unrelated stuff).
If you aren't familiar with how CouchDB views work, you might want to check out their (quite good) documentation on the subject before going on.
by_permalink view includes both a
map and a
reduce which means that (when called with
this view will return data like:
Notice that it's just plain old
JSON. You know what's good at
JSON? That's right. Everything.
There's a problem coming up here, though. In order to get these results we
call a URL like
localhost. We could open up the server to external requests
but then what's to stop someone from just inserting any document, deleting any
document (or database!) they like? Well, it's much simpler to just only expose
the server to the machine it's actually running on. This means that we will
need some backmiddle-end, afterall.
Middle-end w/ Sinatra
is totally awesome... Following the (quite good!) Sinatra (and Rack,
I was able to setup Sinatra in front of my entire site and just
intercept calls to
/api/* as requests Sinatra should actually
attempt to handle. The rest pass through to my static stuff. Here's what the
code might look like:
So far so good. You should now be able to play around with the database a little just using those two actions. With this Sinatra app running, you might write a script like this:
...and running it like:
Now that we have Sinatra as middle-ware-of-sorts for our database we need to use this stuff on the frontend part.
Front-end w/ jQuery
Normally, for this sort of thing, I write it up as a jQuery plugin and include
it on the pages I'll be using it on. Then I'll add it to my site's global
$(document).ready with something along the lines of...
...thus keeping your site-wide onload quite clean, and that's exactly what
I've done for ryanfunduk.com, but you could go lots of ways to
accomplish this. Take a look at the
code I use on this site
or the version written inline in this
of the code in this article.
Sorry this blog has been redone and that stuff isn't there anymore!
As usual there are some enhancements you can make to this. One obvious one
is that since CouchDB handles document revisions for you more-or-less
automatically we can append something unique to the
_id of the
document (say, the user's IP address). This way a user rating an article
more than once will just update their previously created document (assuming
their IP doesn't change, of course).
Other things you could do: Create another Sinatra action and another CouchDB view giving a breakdown of all the ratings that have been made — Perhaps with graphs by date (remember you can just add arbitrary data to documents, why not timestamps?). Or maybe some administration features so you can moderate the system.
Some social stuff: