Mongodb 节点驱动程序 2.0.* 与 Bluebird 2.9.* promisification
Mongodb node driver 2.0.* with Bluebird 2.9.* promisification
所以还有一些关于这个主题的其他查询,例如:
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
创建的集合的示例输出,然后从 returned 数据库中获取集合。一旦我尝试对集合做任何事情,它就会挂起并承诺不会 return 来自它:
{ 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' } }
你可以在 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);
});
精简更真实的版本:
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));
Promise 嵌套是有意将数据库暴露给其余逻辑的。通过全局传递或声明 'db' 可以在不嵌套的情况下完成相同的操作。都试过了,这个最优雅。
默认情况下,mongodb驱动程序总是return一个承诺,如果你不指定回调。但是您可以使用您喜欢的 promises 库指示它 return promises。
下面是使用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);
});
}
您可以阅读 MongoDB 本机驱动程序的源代码:
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
所以还有一些关于这个主题的其他查询,例如: 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
创建的集合的示例输出,然后从 returned 数据库中获取集合。一旦我尝试对集合做任何事情,它就会挂起并承诺不会 return 来自它:
{ 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' } }
你可以在 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);
});
精简更真实的版本:
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));
Promise 嵌套是有意将数据库暴露给其余逻辑的。通过全局传递或声明 'db' 可以在不嵌套的情况下完成相同的操作。都试过了,这个最优雅。
默认情况下,mongodb驱动程序总是return一个承诺,如果你不指定回调。但是您可以使用您喜欢的 promises 库指示它 return promises。
下面是使用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);
});
}
您可以阅读 MongoDB 本机驱动程序的源代码:
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