2015-03-18 11 views
9

Quindi ci sono un paio di altre query intorno a questo tema, quali: How can I promisify the MongoDB native Javascript driver using bluebird?MongoDB nodo conducente 2.0 * con Bluebird 2.9 * promisification

Tuttavia non sembra per affrontare l'ultima versione del driver, che sembra avere problemi quando si cerca di promettere. Attualmente posso ottenere il MongoClient lavorare facendo:

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

Tuttavia, non importa quello che cerco le collezioni non sembrano funzionare utilizzando le *async chiamate, può invocateli ma non hanno mai si risolvono o respinto in modo da basta appendere in un limbo.

Storicamente nelle versioni precedenti si sarebbe solo Promise.promisifyAll(mongodb) e si è fatto, ma non sono sicuro su come gestirlo correttamente nel nuovo driver.

Ecco un esempio di output di una raccolta che è stata creata utilizzando la promessa di promulgazione di mongo connectAsync quindi ottenere la raccolta dal db restituito. Una volta che provo a fare qualcosa sulla raccolta appende appena e promesse non restituiamo da esso:

{ 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' } }

+0

Per chiunque altro guardando questo, in Mong o 2. * sembrano cambiare ciò che viene restituito da determinati metodi, come findAsync ora sembra restituire alcuni modelli enormi piuttosto che i documenti che stavo ottenendo prima, quindi questo problema è una via di mezzo tra dover migrare la logica e dover promettilo correttamente – Grofit

risposta

8

È possibile promisify direttamente dopo che richiede, come esemplificato in bluebird API docs, in questo modo:

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

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

Utilizzando Bluebird 2.9.14 e 2.0.22 MongoDB autista, ho ottenuto questo (semplificato) risultati:

// .... 
    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], 
     // .... 

o interrogato successfu lly come questo:

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

Utilizzando l'oggetto MongoClient funziona così:

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

Faccio quanto sopra e posso vedere che ci sono metodi asincroni su alcune cose, ma l'oggetto 'MongoClient' contiene solo' connect' not 'connectAsync'. Comunque nel tuo esempio implichi che ti colleghi direttamente sull'oggetto mongodb non sull'oggetto 'mongodb.MongoClient' che è elencato nella documentazione: http://mongodb.github.io/node-mongodb-native/2.0/ can si esegue nuovamente il codice e si esegue l'output dell'oggetto 'MongoClient', che potrebbe far luce sull'argomento in quanto il resto potrebbe essere limitato, ma' connectAsync' semplicemente non esiste usando l'esempio sopra riportato. (con MongoClient) – Grofit

+0

Posso confermare che la connessione sopra tramite l'oggetto base mongodb funziona in questo modo, ma gli altri oggetti non si comportano come previsto. Per esempio mi connetto ora usando il modo mostrato sopra, e poi creo una collezione che l'oggetto non sembra assomigliare al tuo. Pubblicherò una modifica con l'output dei miei oggetti della collezione. – Grofit

+0

Ho aggiornato la mia risposta con un esempio usando l'oggetto 'MongoClient'. L'output che ho postato proveniva dall'oggetto base 'MongoDB', non da' db.collection() '. Tuttavia, potrei interrogare il database come al solito usando le funzioni * Async. – victorkohl

1

semplificata e più realistica versione:

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

Promessa di nidificazione è fatto di proposito per esporre db al resto della logica. Lo stesso può essere fatto senza annidamento passando o dichiarando 'db' globalmente. Provato tutto e questo è il più elegante.

8

Per impostazione predefinita, il driver mongodb restituisce sempre una promessa se non si specifica una richiamata. Ma puoi istruirlo a restituire le promesse usando la tua libreria delle promesse preferite.

Ecco un metodo semplice da usare promesse Bluebird quando si utilizza node-mongodb-native 2.0 conducente:

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

Attenzione anche a questa nota: http://bluebirdjs.com/docs/api/resource-management.html – Tom

+0

Se stai usando find, devi agire il cursore prima di chiudere definitivamente il db, ma questo sembra il soluzione migliore. – conradj

+0

Sì, è necessario consumarlo prima della chiusura. Infatti, si preferirebbe lasciare le connessioni aperte, perché è piuttosto costoso connettersi e disconnettersi su ogni query. Ho solo provato a creare una sorta di "esempio a ciclo completo", ma consiglio vivamente di riutilizzare le connessioni. Il driver Mongo può gestire un pool di connessioni in modo quasi trasparente. –

0

Potete leggere l'origine di MongoDB driver originale:

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

Il promiseLibrary può essere impostato Bluebird

Problemi correlati