Some observations on MongoDB & CouchDB

We’ve been using CouchDB at Ocasta Labs on and off for well over a year and are pretty comfortable with it. Recently an requirement for a database cropped up on a project that was standard J2EE Java and it seemed that NoSQL was a good match. Instinct told us that Couch wasn’t right for this but we couldn’t explicitly define the why. I’d recently been doing some reading on MongoDB and it seemed like a better fit. We went ahead and used it. It was the right choice this time.

It turns out the reason it was the right choice was that Mongo is quite traditional. It relies on you having a middle tier where your app logic resides. Couch is more radical and it not only replaces the traditional database but also the middle tier. If, as we did on this particular project, you already have a middle tier then using Couch adds complexity to the solution. Some of the app functionality ends up in the mid-tier and some in Couch. With Mongo you keep doing what you were doing. Query result processing and Map Reduce functions are all defined within the Java, Python, etc. code. When we needed a data import script the logic was all in the script and not split between script and database.

There were times that we struggled with Mongo. One of these was using map/reduce. In Couch you can write and test the map without the reduce which helps. I couldn’t find any easy way to do this in Mongo. Neither could i find many examples of anything other than simple counting exercises and data analysis for Mongo map/reduce when what I wanted to do was some data normalisation. We have a large number of data records imported into Mongo in the form


    {
        "_id" : ObjectId("4d8096e25f234eda61070693"),
        "region" : 9,
        "package" : "M",
        "id" : "534",
        "name" : "channel 534"
    }

We needed a summary view of this data where there was one record for each region/id pair and an array of all possible packages. e.g.


    {
        "_id" : {
            "id" : "534",
            "region" : 9
        },
        "value" : {
            "packages" : [ "M", "M+", "L", "XL" ],
            "name" : "channel 534"
        }
    }

Experience with CouchDB indicated that this was an ideal problem for a map/reduce. I’ve included our solution in the hope that others may find it useful.

    mapfn = function(){
        var detail = {}
        detail.packages = []
        detail.name = this.name
        detail.packages = detail.packages.concat(this.package)
        emit({id: this.id, region: this.region}, detail)
    }

    reducefn = function (key, values) {
        var detail = {}
        detail.packages = []
        values.forEach ( function(val) {
        detail.name = val.name
        detail.packages = detail.packages.concat(val.packages)})
        return detail }

While MongoDB was the right tool for the job this time, we won’t be giving up CouchDB anytime soon. Couch is more than a database. It is at its best when you have a blank slate and then there is no need for a middle tier in your architecture. A pure Couch application is simpler to deploy, upgrade and scale. The CouchDB _changes feed is invaluable. We will be using MongoDB in the future too. Two highly useful, but distinct NoSQL databases every backend developer should be familiar with.

Tags: ,

Comments are closed.