OdeToCode IC Logo

Using system.js in MongoDB (From C#)

Friday, May 17, 2013

The official MongoDB docs recommend that you avoid storing scripts on the server, but there are scenarios where having reusable functions available on the server can be useful. Inside a MapReduce operation, for example.

We’ll start with some JavaScript code encapsulating statistical calculations, and place the code in a file named mathStats.js:

function() {

    var stdDev = function(numbers) {
        // ...  
    };

    var mode = function(numbers) {
        // ...
    };

    var mean = function(numbers) {
        // ...
    };

    return {
        stdDev: stdDev,
        mode: mode,
        mean: mean
    };

};

Note the script must be a function. To use the methods inside, the function must live in the system.js collection. The following C# code can do this:

var sysJs = db.GetCollection("system.js");
var code = File.ReadAllText("pathTo\\mathStats.js");
var codeDocument = new BsonDocument("value", new BsonJavaScript(code));
codeDocument.Add(new BsonElement("_id", "mathStats"));
sysJs.Insert(codeDocument);

It is important to insert the script as the  value attribute of a document, and set the _id of the document to a friendly string name and not an ObjectID value. Failing to follow those two steps can lead to errors like “exception: name has to be a string” and “value has to be set” when you execute commands.

Once the script is loaded, you can use the function from any map, reduce, or finalize function by invoking the function with its friendly _id name. For example:

function(key, value){                      
    var stats = mathStats();
    value.stdDev = stats.stdDev(value.items);               
    return value;
}