So there are a few other queries around this subject such as: How can I promisify the MongoDB native Javascript driver using bluebird?
However it does not seem to address the latest version of the driver, which seems to have issues when trying to promisify. Currently I can get the MongoClient
working by doing:
Promise.promisifyAll(mongodb.MongoClient); // Using .Prototype here fails to promisify
However no matter what I try the Collections do not seem to operate using the *async
calls, it may invoke them but they never get resolved or rejected so they just hang in limbo.
Historically in the previous versions you would just Promise.promisifyAll(mongodb)
and you were done, but I am unsure as to how to correctly handle this in the new driver.
Here is an example output of a collection which has been created using the mongo direct promisification connectAsync
then getting the collection from the returned db. Once I try to do anything on the collection it just hangs and promises dont return from it:
{ 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' } }
You can promisify it directly after requiring, as exemplified on bluebird API docs, like this:
var Promise = require("bluebird");
var MongoDB = Promise.promisifyAll(require("mongodb"));
var util = require('util');
console.log(util.inspect(MongoDB, { showHidden: true }));
Using bluebird 2.9.14 and mongodb driver 2.0.22, I got this (simplified) results:
// ....
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],
// ....
And queried successfully like this:
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);
});
UPDATE
Using the MongoClient
object works as well:
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);
});
By default, mongodb driver always return a promise if you don't specify a callback. But you can instruct it to return promises using your preferred promises library.
Here is a simple method to use bluebird promises when using node-mongodb-native 2.0 driver:
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);
});
}
Streamlined and more realistic version:
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 nesting is done on purpose to expose db to the rest of logic. The same can be done without nesting by either passing or declaring 'db' globally. Tried it all and this one is the most elegant.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With