Search code examples
node.jsmongodbexpresspromisemongoskin

Node.js promises with mongoskin


I'm trying to avoid using callbacks when making mongodb queries. I'm using mongoskin to make calls like so:

req.db.collection('users').find().toArray(function (err, doc) {
  res.json(doc);
});

In many cases I need to make multiple queries so I want to use Node.js promise library but I'm not sure how to wrap these functions as promises. Most of the examples I see are trivial for things like readFile, I'm guessing in this case I would need to wrap toArray somehow? Can this be done or would have to be something implemented by mongoskin?

An example could be any set of callbacks, find/insert, find/find/insert, find/update:

req.db.collection('users').find().toArray(function (err, doc) {
  if (doc) {
    req.db.collection('users').find().toArray(function (err, doc) {
      // etc...
    });
  }
  else {
    // err
  }
});

Solution

  • You can promisify the entire module like so with bluebird:

    var Promise = require("bluebird");
    var mongoskin = require("mongoskin");
    Object.keys(mongoskin).forEach(function(key) {
      var value = mongoskin[key];
      if (typeof value === "function") {
        Promise.promisifyAll(value);
        Promise.promisifyAll(value.prototype);
      }
    });
    Promise.promisifyAll(mongoskin);
    

    This only needs to be done in one place for one time in your application, not anywhere in your application code.

    After that you just use methods normally except with the Async suffix and don't pass callbacks:

    req.db.collection('users').find().toArrayAsync()
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      })
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      })
      .then(function(doc) {
        if (doc) {
          return req.db.collection('users').find().toArrayAsync();
        }
      });
    

    So again, if you call a function like

    foo(a, b, c, function(err, result) {
        if (err) return console.log(err);
        //Code
    });
    

    The promise-returning version is called like:

    fooAsync(a, b, c).then(...)
    

    (Uncaught errors are automatically logged so you don't need to check for them if you are only going to log it)