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

前端 未结 5 496
情书的邮戳
情书的邮戳 2020-11-27 17:41

I\'d like to use the MongoDB native JS driver with bluebird promises. How can I use Promise.promisifyAll() on this library?

相关标签:
5条回答
  • 2020-11-27 17:56

    We have been using the following driver in production for a while now. Its essentially a promise wrapper over the native node.js driver. It also adds some additional helper functions.

    poseidon-mongo - https://github.com/playlyfe/poseidon-mongo

    0 讨论(0)
  • 2020-11-27 18:03

    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);
    
    0 讨论(0)
  • 2020-11-27 18:04

    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;
    }
    
    0 讨论(0)
  • 2020-11-27 18:10

    Version 1.4.9 of mongodb should now be easily promisifiable as such:

    Promise.promisifyAll(mongo.Cursor.prototype);
    

    See https://github.com/mongodb/node-mongodb-native/pull/1201 for more details.

    0 讨论(0)
  • 2020-11-27 18:11

    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 information
    require('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 promises
    using(
        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 processes
    using(
        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.

    0 讨论(0)
提交回复
热议问题