如何使用 bluebird promisify MongoDB 本机 Javascript 驱动程序?

IT技术 javascript mongodb promise bluebird node-mongodb-native
2021-02-14 09:44:30

我想使用带有bluebird promisesMongoDB 本机 JS 驱动程序我怎样才能在这个库上使用Promise.promisifyAll()

5个回答

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

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

var Promise = require("bluebird");
var MongoDB = require("mongodb");
Promise.promisifyAll(MongoDB);
这不起作用,因为github.com/mongodb/node-mongodb-native/blob/1.4/lib/mongodb/...您会看到返回的游标不是从Cursor.prototype.
2021-04-16 09:44:30
@dimadima 你需要PromiseCursor.prototype(上面的代码没有)Cursor
2021-04-29 09:44:30
这不是刚刚var MongoDB = Promise.promisifyAll(require("mongodb"))吗?
2021-04-30 09:44:30
正确,现在你只需要Promiserequire("mongodb"). 例如,所有游标都具有 toArrayAsync 方法。
2021-05-01 09:44:30
@dimadima 我明白了,为每个游标一遍又一遍地创建方法是非常低效的:/
2021-05-07 09:44:30

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

  • Db使用MongoClient静态方法或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
    });

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

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;
}
2021-04-16 09:44:30
如果每次都在 cursor.toArray 上调用 promisify 会很昂贵,那么 promisifyingCursor.prototype呢?
2021-04-18 09:44:30
@BenjaminGruenbaum:是的,我意识到我Async在关闭标签后伪造了 - 刚修好。从参考答案中得到的印象是光标不是从原型构建的。现在测试一下。
2021-04-18 09:44:30
另外,您是不是缺少Async“现在您可以”部分中前缀?
2021-05-01 09:44:30
此外,您可能也想Promise MongoClient.prototype 而不是 MongoClient 。
2021-05-15 09:44:30

我知道这已被多次回答,但我想添加有关此主题的更多信息。根据 Bluebird 自己的文档,您应该使用“使用”来清理连接并防止内存泄漏。 Bluebird 中的资源管理

我四处寻找如何正确地做到这一点,但信息很少,所以我想我会分享我经过多次反复试验后的发现。我在下面(餐厅)使用的数据来自 MongoDB 示例数据。你可以在这里得到:MongoDB 导入数据

// 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 书做事的人。

的 1.4.9 版mongodb现在应该可以轻松实现:

Promise.promisifyAll(mongo.Cursor.prototype);

有关更多详细信息,请参阅https://github.com/mongodb/node-mongodb-native/pull/1201

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

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