How can I promisify the MongoDB native Javascript driver using bluebird? How can I promisify the MongoDB native Javascript driver using bluebird? mongodb mongodb

How can I promisify the MongoDB native Javascript driver using bluebird?


The 2.0 branch documentation contains a better promisification guide https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification

It actually has mongodb example which is much simpler:

var Promise = require("bluebird");var MongoDB = require("mongodb");Promise.promisifyAll(MongoDB);


When using Promise.promisifyAll(), it helps to identify a target prototype if your target object must be instantiated. In case of the MongoDB JS driver, the standard pattern is:

  • Get a Db object, using either MongoClient static method or the Db constructor
  • Call Db#collection() to get a Collection object.

So, borrowing from https://stackoverflow.com/a/21733446/741970, you can:

var Promise = require('bluebird');var mongodb = require('mongodb');var MongoClient = mongodb.MongoClient;var Collection = mongodb.Collection;Promise.promisifyAll(Collection.prototype);Promise.promisifyAll(MongoClient);

Now you can:

var client = MongoClient.connectAsync('mongodb://localhost:27017/test')    .then(function(db) {        return db.collection("myCollection").findOneAsync({ id: 'someId' })    })    .then(function(item) {      // Use `item`    })    .catch(function(err) {        // An error occurred    });

This gets you pretty far, except it'll also help to make sure the Cursor objects returned by Collection#find() are also promisified. In the MongoDB JS driver, the cursor returned by Collection#find() is not built from a prototype. So, you can wrap the method and promisify the cursor each time. This isn't necessary if you don't use cursors, or don't want to incur the overhead. Here's one approach:

Collection.prototype._find = Collection.prototype.find;Collection.prototype.find = function() {    var cursor = this._find.apply(this, arguments);    cursor.toArrayAsync = Promise.promisify(cursor.toArray, cursor);    cursor.countAsync = Promise.promisify(cursor.count, cursor);    return cursor;}


I know this has been answered several times, but I wanted to add in a little more information regarding this topic. Per Bluebird's own documentation, you should use the 'using' for cleaning up connections and prevent memory leaks.Resource Management in Bluebird

I looked all over the place for how to do this correctly and information was scarce so I thought I'd share what I found after much trial and error. The data I used below (restaurants) came from the MongoDB sample data. You can get that here: MongoDB Import Data

// Using dotenv for environment / connection informationrequire('dotenv').load();var Promise = require('bluebird'),    mongodb = Promise.promisifyAll(require('mongodb'))    using = Promise.using;function getConnectionAsync(){    // process.env.MongoDbUrl stored in my .env file using the require above    return mongodb.MongoClient.connectAsync(process.env.MongoDbUrl)        // .disposer is what handles cleaning up the connection        .disposer(function(connection){            connection.close();        });}// The two methods below retrieve the same data and output the same data// but the difference is the first one does as much as it can asynchronously// while the 2nd one uses the blocking versions of each// NOTE: using limitAsync seems to go away to never-never land and never come back!// Everything is done asynchronously here with promisesusing(    getConnectionAsync(),    function(connection) {        // Because we used promisifyAll(), most (if not all) of the        // methods in what was promisified now have an Async sibling        // collection : collectionAsync        // find : findAsync        // etc.        return connection.collectionAsync('restaurants')            .then(function(collection){                return collection.findAsync()            })            .then(function(data){                return data.limit(10).toArrayAsync();            });    }// Before this ".then" is called, the using statement will now call the// .dispose() that was set up in the getConnectionAsync method).then(    function(data){        console.log("end data", data);    });// Here, only the connection is asynchronous - the rest are blocking processesusing(    getConnectionAsync(),    function(connection) {        // Here because I'm not using any of the Async functions, these should        // all be blocking requests unlike the promisified versions above        return connection.collection('restaurants').find().limit(10).toArray();    }).then(    function(data){        console.log("end data", data);    });

I hope this helps someone else out who wanted to do things by the Bluebird book.