Node.js & MongoDB - No ORM needed, but I do want something...
Node.js
Wednesday, 29 September 2010 12:09

One thing I love about MongoDB's document-oriented approach is that there is no longer a need for an ORM (object relational mapper) because there is nothing to map. You can just store your object directly. However, I would still like a layer to reduce the complexity of interfacing with MongoDB. For example, working with MongoDB requires quite a few layers of nested callbacks and I don't want to deal with that everywhere.

The first library I came across to ease use of MongoDB was mongoose. It seems to be quite nice, but it has one problem. It is trying to be an ORM where an ORM is not needed! I don’t want to create my model using the ORM tool. I shouldn’t have to do that with MongoDB. I should be able to create my models completely separate and if I want to I might not even make a model in some cases.

So what I really want is just a simple layer over MongoDB to take care of connections, reduce the number of callbacks I have to deal with and make error handling more simple. Not an ORM. So I started to write a class called DataProvider that does just this. It works with models by defining an interface they must implement in order to work with it (a very simple interface). Keep in mind this is very incomplete. I only implemented what I need at the moment.

DataProvider.js

var mongodb = require('mongodb'),
    sys = require('sys');
 
var DataProvider = function(cfg) {
    cfg = cfg || {};
 
    if (!cfg.host) { throw new Error('Missing host config.'); }
    cfg.port = cfg.port || 27017;
    if (!cfg.dbname) { throw new Error('Missing dbname config.'); }
 
    this.cfg = cfg;
};
 
DataProvider.prototype.save = function(persistable, callback) {
    var db = new mongodb.Db(
        this.cfg.dbname,
        new mongodb.Server(this.cfg.host, this.cfg.port, {auto_reconnect:true}),
        {strict:false}
    );
    db.addListener('error', callback);
    db.open(function(err, db) {
        if (err) { return callback(err) }
        db.createCollection(persistable.getCollectionName(), function(err, collection) {
            if (err) { return callback(err) }
            collection.insert(persistable.toObject(), function(err, docs) {
                db.close();
                callback(null, persistable);
            });
        });
    });
};
 
exports.DataProvider = DataProvider;

Persistable.js

var Persistable = function(){};
 
Persistable.prototype.getCollectionName = function() { throw new Error('not implemented') };
 
Persistable.prototype.toObject = function() { throw new Error('not implemented') };
 
Persistable.prototype.initFromObject = function() { throw new Error('not implemented') };
 
exports.Persistable = Persistable;
 

blog comments powered by Disqus