views:

770

answers:

3

Rails uses the concept of migrations to deal with model changes using the ActiveRecord API.

CouchDB uses JSON (nested maps and arrays) to represent its model objects.

In working with CouchDB so far, I don't see good ways of recognizing when the document's structure has changed (other than being disciplined as a developer), or for migrating documents from an old to a new model.

Are there existing features or do you have best practices for handling model changes in CouchDB?

+3  A: 

Check out ActiveCouch: http://code.google.com/p/activecouch/

CouchDB is schema-less on purpose, so there is not a 1-to-1 mapping of concepts from the ActiveRecord migrations to a CouchDB equivalent. However, ActiveCouch does include migrations for CouchDB's "views."

Ian Terrell
Looks like activecouch is now on GitHub - http://github.com/arunthampi/activecouch/tree/master
Evan
+7  A: 

Time for RDBMS de-brainwashing. :)

One of the biggest points of couchdb's schema-less design is directly aimed at preventing the need for migrations. The JSON representation of objects makes it easy to just duck type your objects.

For example, given that you have a blog type web app with posts and whatever fancy things people store in a blog. Your post documents have fields like author, title, created at, etc. Now you come along and think to yourself, "I should track what phase the moon is in when I publish my posts..." you can just start adding moon_phase as an attribute to new posts.

If you want to be complete you'd go back and add moon_phase to old posts, but that's not strictly necessary.

In your views, you can access moon_phase as an attribute. And it'll be null or cause an exception or something. (Not a JS expert, I think null is the right answer)

Thing is, it doesn't really matter. If you feel like changing something just change it. Though make sure your views understand that change. Which in my experience doesn't really require much.

Also, if you're really paranoid, you might store a version/type attribute, as in:

{
   _id: "foo-post",
   _rev: "23490AD",
   type: "post",
   typevers: 0,
   moon_phase: "full"
}

Hope that helps.

Paul J. Davis
+3  A: 

If you're into having schemas and still want to use CouchDB you get an "impedance mismatch".

Nevertheless, having "migrations" is not that hard. Add a schema_version element to each document. Then have your "document reading function" include updating. Something like this:

def read(doc_id):
    doc = db.get(doc_id)
    if doc.schema_version == 1:
        # version 1 had names broken down too much
        doc.name = "%s %s" % (doc.first, doc.last)
        del doc.first
        del doc.last
        doc.schema_version = 2
        db.put(doc)
    if doc.schema_version == 2: weight
        # version 2 used kg instead of g
        doc.weight_g = doc.weight_kg * 1000
        del doc.volume_kg
        doc.schema_version = 3
        db.put(doc)
    return doc

If you want to upgrade the whole DB at once just call read(doc_id) for every document.

mdorseif