Map-reduce with Mongoose, the easy way

Sun Jul 01 2012 22:24:00 GMT+0000 (Coordinated Universal Time)

Update: Since the time of writing, Mongoose now has a proper support for Map-Reduce.

What’s with all the poor documentation of many node modules out there? You could expect widely adapted modules to at least have a function reference, but they keep insisting on only providing “guides” and if you want to know more you have to look at the (often very messy) source code. When it comes to Mongoose, the guide leaves a lot to be desired, but the annotated api docs comes to the rescue.

When I wanted to preform a map-reduce though, neither the guide nor the api docs were of any help. Google gave me a bunch of outdated methods, like calling executeDbCommand on the raw mongodb connection. According to this issue on github opened 6 months ago “its not included in the docs b/c its not really supported yet”. There’s a commit that has added support for mapReduce in response to that issue, but it has yet to be merged with the master branch.

Until then, it turns out, you can just call Model.collection.mapReduce which is a shorthand for the native MongoDB MapReduce command documented here.

Model.collection.mapReduce({
    mapFunction,
    reduceFunction,
    options,
    callback
});

For example, this is what I use (with the help from the map, reduce and finalize functions from this gist) to get a random 50 documents out of a collection:

Model.collection.mapReduce(
    "function(){emit(0,{k:this,v:Math.random()})}",
    "function(k,v){var a=[];v.forEach(function(x){a=a.concat(x.a?x.a:x)});return{a:a.sort(function(a,b){return a.v-b.v}).slice(0,50)}}",
    { 
        query: query,
        out: { inline: 1 },
        finalize: "function(k,v){return v.a?v.a.map(function(x){return x.k}):[v.k]}",
    },
    function(err, doc) {
        console.log(doc);
    }
);
Who?
What?
My personal portfolio of things I come up with when I'm bored.