【问题标题】:How can I promisify the MongoDB native Javascript driver using bluebird?如何使用 bluebird 承诺 MongoDB 本机 Javascript 驱动程序?
【发布时间】:2014-07-09 10:14:18
【问题描述】:

我想将MongoDB native JS driverbluebird promises 一起使用。我如何在这个库上使用Promise.promisifyAll()

【问题讨论】:

  • mongo 2.0 及更高版本可让您告诉 mongo 驱动程序您要使用 bluebird:easyusedev.wordpress.com/2015/10/07/…
  • 在我看来这是最好的解决方案,如果你把它作为答案而不是评论放在里面会很好。

标签: javascript mongodb promise bluebird node-mongodb-native


【解决方案1】:

我们在生产环境中使用以下驱动程序已有一段时间了。它本质上是原生 node.js 驱动程序的承诺包装器。它还添加了一些额外的辅助函数。

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

【讨论】:

    【解决方案2】:

    我知道这个问题已经回答了好几次了,但我想补充一点关于这个话题的信息。根据 Bluebird 自己的文档,您应该使用“使用”来清理连接并防止内存泄漏。 Resource Management in Bluebird

    我到处寻找如何正确地做到这一点,但信息很少,所以我想我会分享我在反复试验后发现的东西。我在下面使用的数据(餐厅)来自 MongoDB 示例数据。你可以在这里得到: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);
        }
    );
    

    我希望这可以帮助其他想要按照 Bluebird 书做事的人。

    【讨论】:

      【解决方案3】:

      2.0 分支文档包含更好的承诺指南https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification

      它实际上有更简单的 mongodb 示例:

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

      【讨论】:

      • @dimadima 你需要承诺Cursor.prototype(上面的代码就是这样)而不是Cursor
      • 这不起作用,因为github.com/mongodb/node-mongodb-native/blob/1.4/lib/mongodb/…;您会看到返回的光标不是从 Cursor.prototype 构建的。
      • @dimadima 我明白了,为每个光标一遍又一遍地创建方法效率非常低:/
      • 现在不就是var MongoDB = Promise.promisifyAll(require("mongodb"))吗?
      • 正确,现在你只需要promisify require("mongodb")。然后所有游标都有 toArrayAsync 方法,例如。
      【解决方案4】:

      mongodb 的 1.4.9 版现在应该很容易被承诺:

      Promise.promisifyAll(mongo.Cursor.prototype);
      

      更多详情请见https://github.com/mongodb/node-mongodb-native/pull/1201

      【讨论】:

        【解决方案5】:

        使用Promise.promisifyAll() 时,如果您的目标对象必须被实例化,它有助于识别目标原型。对于 MongoDB JS 驱动程序,标准模式是:

        • 使用MongoClient 静态方法或Db 构造函数获取Db 对象
        • 调用Db#collection() 以获取Collection 对象。

        所以,借用https://stackoverflow.com/a/21733446/741970,你可以:

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

        现在你可以:

        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
            });
        

        这会让你走得很远,除了它还有助于确保Collection#find() 返回的Cursor 对象也被承诺。在 MongoDB JS 驱动程序中,Collection#find() 返回的游标不是从原型构建的。因此,您可以包装该方法并每次都承诺游标。如果您不使用游标,或者不想产生开销,则这不是必需的。这是一种方法:

        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;
        }
        

        【讨论】:

        • 在 cursor.toArray 上调用 promisify 如果每次都这样做会很昂贵,那么 promisify Cursor.prototype 呢?
        • 另外,你是不是错过了“现在你可以”部分中的Async 前缀?
        • @BenjaminGruenbaum:是的,我意识到我在关闭标签后伪造了 -Async。刚刚修好了。从引用的答案中得到的印象是光标不是从原型构建的。现在测试一下。
        • 另外,你可能也想承诺 MongoClient.prototype 而不是 MongoClient。
        猜你喜欢
        • 2016-07-27
        • 2014-07-15
        • 2014-09-07
        • 2016-04-10
        • 2023-03-19
        • 2016-12-05
        • 1970-01-01
        • 2018-02-01
        • 2016-11-09
        相关资源
        最近更新 更多