web-dev-qa-db-fra.com

Comment puis-je promisifier le pilote Javascript natif MongoDB avec bluebird?

J'aimerais utiliser le pilote JS natif MongoDB avec les promesses bluebird . Comment utiliser Promise.promisifyAll() sur cette bibliothèque?

24
Dmitry Minkovsky

La documentation de branche 2.0 contient un meilleur guide de promisification https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification

Il a en fait un exemple mongodb qui est beaucoup plus simple:

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

Lors de l'utilisation de Promise.promisifyAll(), il est utile d'identifier un prototype cible si votre objet cible doit être instancié. Dans le cas du pilote MongoDB JS, le modèle standard est le suivant:

  • Obtenez un objet Db à l'aide de la méthode statique MongoClient ou du constructeur Db
  • Appelez Db#collection() pour obtenir un objet Collection.

Ainsi, en empruntant à https://stackoverflow.com/a/21733446/741970 , vous pouvez:

var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var Collection = mongodb.Collection;

Promise.promisifyAll(Collection.prototype);
Promise.promisifyAll(MongoClient);

Maintenant vous pouvez:

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

Cela vous mène assez loin, sauf que cela vous aidera également à vous assurer que les objets Cursor renvoyés par Collection#find() sont également promis. Dans le pilote MongoDB JS, le curseur renvoyé par Collection#find() n'est pas construit à partir d'un prototype. Ainsi, vous pouvez envelopper la méthode et promisifier le curseur à chaque fois. Ce n'est pas nécessaire si vous n'utilisez pas de curseurs ou si vous ne voulez pas générer de frais supplémentaires. Voici une approche:

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;
}
18
Dmitry Minkovsky

Je sais que cela a été répondu à plusieurs reprises, mais je voulais ajouter un peu plus d'informations sur ce sujet. Selon la propre documentation de Bluebird, vous devez utiliser l'option 'using' pour nettoyer les connexions et éviter les fuites de mémoire . Gestion des ressources dans Bluebird

J'ai cherché partout comment faire cela correctement et l'information était rare, alors j'ai pensé partager ce que j'ai trouvé après de nombreux essais et erreurs. Les données que j'ai utilisées ci-dessous (restaurants) proviennent de l'échantillon de données MongoDB. Vous pouvez l'obtenir ici: Données d'importation 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);
    }
);

J'espère que cela aidera quelqu'un d'autre à vouloir faire ce qui est écrit dans le livre Bluebird.

10
Allen Underwood

La version 1.4.9 de mongodb devrait maintenant être facilement promissable en tant que telle:

Promise.promisifyAll(mongo.Cursor.prototype);

Voir https://github.com/mongodb/node-mongodb-native/pull/1201 pour plus de détails.

7
knpwrs

Nous utilisons le pilote suivant en production depuis un moment. Il s’agit essentiellement d’un wrapper de promesse sur le pilote node.js natif. Il ajoute également des fonctions d'assistance supplémentaires.

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

0
Rajan