【问题标题】:Mongodb node driver 2.0.* with Bluebird 2.9.* promisificationMongodb node driver 2.0.* with Bluebird 2.9.* promisification
【发布时间】:2015-05-21 01:07:46
【问题描述】:

因此,围绕这个主题还有一些其他查询,例如: How can I promisify the MongoDB native Javascript driver using bluebird?

但是它似乎没有解决最新版本的驱动程序,这在尝试承诺时似乎有问题。目前我可以通过以下方式让MongoClient 工作:

Promise.promisifyAll(mongodb.MongoClient); // Using .Prototype here fails to promisify

但是,无论我尝试什么,集合似乎都无法使用 *async 调用进行操作,它可能会调用它们,但它们永远不会得到解决或拒绝,因此它们只是处于不确定状态。

过去,在以前的版本中,您只需 Promise.promisifyAll(mongodb) 就完成了,但我不确定如何在新驱动程序中正确处理此问题。

这是一个使用 mongo 直接承诺 connectAsync 创建的集合的示例输出,然后从返回的数据库中获取集合。一旦我尝试对集合做任何事情,它就会挂起并承诺不会从中返回:

{ s: { pkFactory: { [Function: ObjectID] index: 14727641, createPk: [Function: createPk], createFromTime: [Function: createFromTime], createFromHexString: [Function: createFromHexString], isValid: [Function: isValid], ObjectID: [Circular], ObjectId: [Circular], createPkAsync: [Object], createFromTimeAsync: [Object], createFromHexStringAsync: [Object], isValidAsync: [Object], bindAsync: [Object], toStringAsync: [Object], callAsync: [Object], applyAsync: [Object], lazyAsync: [Object], throttleAsync: [Object], debounceAsync: [Object], delayAsync: [Object], everyAsync: [Object], cancelAsync: [Object], afterAsync: [Object], onceAsync: [Object], fillAsync: [Object] }, db: { domain: [Object], _events: {}, _maxListeners: undefined, s: [Object], serverConfig: [Getter], bufferMaxEntries: [Getter], databaseName: [Getter], options: [Getter], native_parser: [Getter], slaveOk: [Getter], writeConcern: [Getter] }, topology: { domain: [Object], _events: [Object], _maxListeners: undefined, connectTimeoutMS: 500, s: [Object], bson: [Getter], isMasterDoc: [Getter], poolSize: [Getter], autoReconnect: [Getter], host: [Getter], port: [Getter], emitOpen: false, socketTimeoutMS: 0 }, dbName: 'some-db-name', options: {}, namespace: 'some-namespace', readPreference: null, raw: undefined, slaveOk: false, serializeFunctions: undefined, internalHint: null, collectionHint: null, name: 'some-collection-name' } }

【问题讨论】:

  • 对于其他看到这个的人来说,在 Mongo 2.* 他们似乎改变了从某些方法返回的内容,比如 findAsync 现在似乎返回了一些巨大的模型,而不是我之前得到的文档,所以这个问题是必须迁移逻辑和必须正确承诺之间的中间路径。

标签: javascript node.js mongodb promise bluebird


【解决方案1】:

你可以在require之后直接promisify,比如bluebird API docs,像这样:

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

console.log(util.inspect(MongoDB, { showHidden: true }));

使用 bluebird 2.9.14 和 mongodb 驱动程序 2.0.22,我得到了这个(简化的)结果:

  // ....
  Collection: 
   { [Function]
     [length]: 6,
     [name]: '',
     [arguments]: [Getter/Setter],
     [caller]: [Getter/Setter],
     [prototype]: 
      { [constructor]: [Circular],
        collectionName: [Getter],
        // .... 
        findAsync: [Object],
        insertOneAsync: [Object],
        insertManyAsync: [Object],
        bulkWriteAsync: [Object],
        insertAsync: [Object],
        updateOneAsync: [Object],
        replaceOneAsync: [Object],
        updateManyAsync: [Object],
        updateAsync: [Object],
        deleteOneAsync: [Object],
        removeOneAsync: [Object],
        deleteManyAsync: [Object],
        removeManyAsync: [Object],
        removeAsync: [Object],
        saveAsync: [Object],
        findOneAsync: [Object],
        // ....

并且这样查询成功:

MongoDB.connectAsync('mongodb://localhost:27017/test').then(function(db) {
    return db.collection("orders").findOneAsync({});
}).then(function(orders) {
    console.log(orders);
}).catch(function(err) {
    console.log(err);
});

更新

使用MongoClient 对象也可以:

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

MongoClient.connectAsync('mongodb://localhost:27017/test').then(function(db) {
    return db.collection("orders").find({}).toArrayAsync();
}).then(function(orders) {
    console.log(orders)
}).catch(function(err) {
    console.log(err);
});

【讨论】:

  • 我做了上面的操作,我可以看到有些东西有异步方法,但是MongoClient对象只包含connect而不是connectAsync。但是,在您的示例中,您暗示您直接在 mongodb 对象上连接,而不是在文档中列出的 mongodb.MongoClient 对象上:mongodb.github.io/node-mongodb-native/2.0 您可以再次运行您的代码并输出 MongoClient 对象然后可能会脱落一些对此事的轻描淡写,因为它的其余部分可以很好地绑定,但connectAsync 使用上面的示例根本不存在。 (使用 MongoClient)
  • 我可以确认通过基础 mongodb 对象的上述连接以这种方式工作,但其他对象仍然没有按预期运行。例如,我现在使用上面显示的方式连接,然后创建一个对象看起来不像你的集合。我将使用我的集合对象的输出发布一个编辑。
  • 我用MongoClient 对象的示例更新了我的答案。我发布的输出来自基础MongoDB 对象,而不是来自db.collection()。不过,我可以像往常一样使用 *Async 函数查询数据库。
  • 我会将您的答案标记为正确,因为这里似乎还有更多内容。由于 2.* 版本添加了一些新方法并稍微改变了现有方法的行为,所以我认为我遇到了一些问题,例如 remove 无法按预期工作,但如果我移至 deleteOne 或 @987654339 @它工作正常,所以你的断言是正确的,但是任何其他有类似问题的人都需要考虑将他们的异步调用迁移到我认为的较新的调用。再次感谢您的帮助。
【解决方案2】:

默认情况下,如果你不指定回调,mongodb 驱动程序总是返回一个承诺。但是您可以指示它使用您首选的承诺库返回承诺。

这是使用node-mongodb-native 2.0驱动程序时使用bluebird promises的简单方法:

var Promise = require("bluebird");
var MongoClient = require("mongodb").MongoClient; // Doesn't require promisification

/*...*/
function saveData(data) {
  MongoClient
    .connect(MONGO_CONNECTION_STRING, {
      promiseLibrary: Promise // Here you instruct to use bluebird
    })
    .then(function(db) {
      return db
        .collection('myCollection')
        .insert(data)
        .finally(db.close.bind(db))
    })
    .catch(function(err) {
      console.error("ERROR", err);
    });
}

【讨论】:

  • 如果您使用的是 find,那么您必须在最终关闭数据库之前操作光标,但这似乎是最好的解决方案。
  • 是的,你需要在关闭前消耗它。事实上,人们更愿意让连接保持打开状态,因为每次查询都连接和断开连接非常昂贵。我只是尝试创建一种“全周期示例”,但我强烈建议重用您的连接。 Mongo 驱动几乎可以透明地管理连接池。
【解决方案3】:

精简且更真实的版本:

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

MongoDB.MongoClient.connectAsync('mongodb://localhost:27017/test')
  .then(function(db) { // Expose db to query logic
    // need to return a promise to let outer catch handle it
    return db.collection("orders").find({}).toArrayAsync()
      .then(function (orders) {
        console.log(orders);
      })
      // Ensure that db is closed at the end no matter what...
      .finally(db.close.bind(db)); 
      // No need for another catch here, the outer one will handle it 
  })
  .catch(console.log.bind(console));

承诺嵌套是故意将 db 暴露给其余逻辑的。通过全局传递或声明 'db' 可以在不嵌套的情况下完成相同的操作。都试过了,这个是最优雅的。

【讨论】:

    【解决方案4】:

    可以阅读MongoDB Native Driver的源码:

    MongoClient.connect = function(url, options, callback) {
      var args = Array.prototype.slice.call(arguments, 1);
      callback = typeof args[args.length - 1] == 'function' ? args.pop() : null;
      options = args.length ? args.shift() : null;
      options = options || {};
    
      // Get the promiseLibrary
      var promiseLibrary = options.promiseLibrary;
    
      // No promise library selected fall back
      if(!promiseLibrary) {
        promiseLibrary = typeof global.Promise == 'function' ?
          global.Promise : require('es6-promise').Promise;
      }
    
      // Return a promise
      if(typeof callback != 'function') {
        return new promiseLibrary(function(resolve, reject) {
          connect(url, options, function(err, db) {
            if(err) return reject(err);
            resolve(db);
          });
        });
      }
    
      // Fallback to callback based connect
      connect(url, options, callback);
    }
    

    promiseLibrary可以设置Bluebird

    【讨论】:

      猜你喜欢
      • 2015-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多