Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep DRY when using node-mongodb-native

db.open(function(err,db){
  //handle error
  db.collection("book",function(err, collection){
     //handle error
     collection.doSomething1(... function(err, result){
         //handle error
         collection.doSomething2(... function(err, result){
            ...
         })
     })
  })
})

but we wont wrote db.open every time when we want do something, but we must make sure that db has opened when we use it.

we still wont like handle error every time in the same code.

we can also reuse the collection.

just like this

errorHandledDB.doSomething1("book",... function(result){
    errorHandledDB.doSomething2("book",...function(result){
        ...
    })
})
like image 972
guilin 桂林 Avatar asked Feb 28 '11 07:02

guilin 桂林


2 Answers

I implemented a server-application using mongodb for logging. I implemented data access using some provider classes, as shown in the example.

provider.filelog.js

var Db= require('mongodb/db').Db,
  ObjectID= require('mongodb/bson/bson').ObjectID,
  Server= require('mongodb/connection').Server,
  log = require('lib/common').log;

FilelogProvider = function (host, port, database) {
  this.db= new Db(database, new Server(host, port, {auto_reconnect: true}, {}));
  this.db.open(function(){});
};

FilelogProvider.prototype.getCollection= function(callback) {
  this.db.collection('filelogs', function(error, log_collection) {
    if (error) callback(error);
    else {
      log_collection.ensureIndex([[ 'created', 1 ]], false, function(err, indexName) {
        if (error) callback(error);
        callback(null, log_collection);
      });
    }
  });
};

FilelogProvider.prototype.findAll = function(callback) {
    this.getCollection(function(error, log_collection) {
      if (error) callback(error);
      else {
        log_collection.find(function(error, cursor) {
          if (error) callback(error);
          else {
            cursor.toArray(function(error, results) {
              if (error) callback(error);
              else callback(null, results);
            });
          }
        });
      }
    });
};

Since i use Grasshopper as my http-middleware, i can easily inject the providers using the DI functionality provided by gh:

server.js

gh.addToContext({
  providers: {
      filelog: new FilelogProvider(conf.mongodb_host, conf.mongodb_port, conf.mongodb_database),
      status: new ServerstatusProvider(conf.mongodb_host, conf.mongodb_port, conf.mongodb_database)
  },
  log: log
});

Accessing the providers in every controller function is now a breeze:

gh.get('/serve',  function() {
  this.providers.filelog.findAll(function(err, res) {
    // access data here
  });
});

This implementation is pretty specific to Grasshopper (as it's using DI) but i think you'll get the idea. I also implemented a solution using express and mongoose, you find it here. This solution is a bit cleaner than using the native driver, as it exposes models to use against the database.

Update

Just for the sake of it: if you really want to stick to the DRY-principle, stop tinkering on an ORM implementation yourself and use Mongoose. If you need special functionality like Map/Reduce, you still can use the native driver (on which Mongoose is built).

like image 158
schaermu Avatar answered Nov 10 '22 11:11

schaermu


Answer my own question. Because there is no more good options, I do it myself, I start a project to simplify it, check node-mongoskin.

like image 35
guilin 桂林 Avatar answered Nov 10 '22 13:11

guilin 桂林