¿Cómo usar MongoDB con promesas en Node.js?

82

He estado tratando de descubrir cómo usar MongoDB con Node.js y en los documentos parece que la forma sugerida es usar devoluciones de llamada. Ahora, sé que es solo una cuestión de preferencia, pero realmente prefiero usar promesas.

El problema es que no encontré cómo usarlos con MongoDB. De hecho, probé lo siguiente:

var MongoClient = require('mongodb').MongoClient;

var url = 'mongodb://localhost:27017/example';

MongoClient.connect(url).then(function (err, db) {
    console.log(db);
});

Y el resultado es undefined. En ese caso, parece que esta no es la forma de hacerlo.

¿Hay alguna forma de usar mongo db dentro de Node con promesas en lugar de devoluciones de llamada?

user1620696
fuente
guru99.com/node-js-promise-generator-event.html ¿¿Este tutorial es incorrecto ???
Ravi Shanker Reddy

Respuestas:

118

Tu enfoque es casi correcto, solo un pequeño error en tu argumento

var MongoClient = require('mongodb').MongoClient
var url = 'mongodb://localhost:27017/example'
MongoClient.connect(url)
  .then(function (db) { // <- db as first argument
    console.log(db)
  })
  .catch(function (err) {})
Verde
fuente
11
¡Exactamente! MongoDB Node.js controlador 2.x "Devuelve: Promise si no hay devolución de llamada pasaron" entre otras cosas por MongoClient.connect. Si tiene node.js <4 sin las promesas de ES6 integradas, también puede usar un ajuste de promesa compatible con ES6 o proporcionar una implementación de promesa compatible con ES6 mediante la promiseLibraryopción de MongoClient.connect.
VolkerM
5
Según algunas pruebas, si se conecta a la URL mongodb//localhost:27017(sin especificar una base de datos), obtiene un mongoclient, por lo que debe llamar mongoclient.db('example'). Ver mongodb.github.io/node-mongodb-native/api-generated/…
PatS
22

También puede hacer async / await

async function main(){
 let client, db;
 try{
    client = await MongoClient.connect(mongoUrl, {useNewUrlParser: true});
    db = client.db(dbName);
    let dCollection = db.collection('collectionName');
    let result = await dCollection.find();   
    // let result = await dCollection.countDocuments();
    // your other codes ....
    return result.toArray();
 }
 catch(err){ console.error(err); } // catch any mongo error here
 finally{ client.close(); } // make sure to close your connection after
}

ginad
fuente
Podría besar tu cara ahora mismo. Esta fue la mejor y más simple respuesta que he encontrado en horas.
Rob E.
Esta es la respuesta más simple, más reciente, más completa y actualizada posible. Muchas gracias.
keuluu
19

Dado que ninguna de las respuestas anteriores menciona cómo hacer esto sin bluebird o q o cualquier otra biblioteca elegante, permítanme agregar mis 2 centavos en esto.

Así es como se hace una inserción con promesas nativas de ES6

    'use strict';

const
    constants = require('../core/constants'),
    mongoClient = require('mongodb').MongoClient;



function open(){

    // Connection URL. This is where your mongodb server is running.
    let url = constants.MONGODB_URI;
    return new Promise((resolve, reject)=>{
        // Use connect method to connect to the Server
        mongoClient.connect(url, (err, db) => {
            if (err) {
                reject(err);
            } else {
                resolve(db);
            }
        });
    });
}

function close(db){
    //Close connection
    if(db){
        db.close();
    }
}

let db = {
    open : open,
    close: close
}

module.exports = db;

Definí mi método open () como el que devuelve una promesa. Para realizar una inserción, aquí está mi fragmento de código a continuación

function insert(object){
    let database = null;
    zenodb.open()
    .then((db)=>{
        database = db;
        return db.collection('users')    
    })
    .then((users)=>{
        return users.insert(object)
    })
    .then((result)=>{
        console.log(result);
        database.close();
    })
    .catch((err)=>{
        console.error(err)
    })
}



insert({name: 'Gary Oblanka', age: 22});

Espero que ayude. Si tiene alguna sugerencia para mejorar esto, hágamelo saber ya que estoy dispuesto a mejorar :)

PirateApp
fuente
13
Envuelve una promesa en otra promesa. Los métodos MongoClient ya están devolviendo una promesa, y no es necesario volver a ajustar esto. Este es un patrón anti-promesa típico.
Westor
4
Llegará meses después, pero la respuesta de @ Green 20 minutos después de la publicación original utiliza el soporte de promesa nativo de mongodb.MongoClient y no bibliotecas de promesas extrañas.
Owen
2
Esta debería ser la respuesta correcta, ya que no depende de bibliotecas de promesas de terceros.
GlGuru
@west o ¿cómo devolverá una promesa del método open () sin envolverla en una nueva Promesa? Creo que esta es la única forma.
Abhishek Nalin
1
@AbhishekNalin El método de conexión de MongoDB (al menos en las versiones más recientes) devuelve una promesa. Por lo tanto, simplemente podría escribir 'mongoClient.connect (url) .then (...)' o en este método abierto devolvería mongoClient.connect (url). Puede deshacerse de la devolución de llamada. El caso de error es detectado por la última captura aquí.
Westor
11

Esta es una respuesta general para ¿Cómo usar MongoDB con promesas en Node.js?

mongodb devolverá una promesa si se omite el parámetro de devolución de llamada

Antes de convertirse en Promise

var MongoClient = require('mongodb').MongoClient,
dbUrl = 'mongodb://db1.example.net:27017';

MongoClient.connect(dbUrl,function (err, db) {
    if (err) throw err
    else{
        db.collection("users").findOne({},function(err, data) {
            console.log(data)
        });
    }
})

Después de convertir a Promise

//converted
MongoClient.connect(dbUrl).then(function (db) {
    //converted
    db.collection("users").findOne({}).then(function(data) {
         console.log(data)
    }).catch(function (err) {//failure callback
         console.log(err)
    });
}).catch(function (err) {})

En caso de que necesite manejar múltiples solicitudes

MongoClient.connect(dbUrl).then(function (db) {

   /*---------------------------------------------------------------*/

    var allDbRequest = [];
    allDbRequest.push(db.collection("users").findOne({}));
    allDbRequest.push(db.collection("location").findOne({}));
    Promise.all(allDbRequest).then(function (results) {
        console.log(results);//result will be array which contains each promise response
    }).catch(function (err) {
         console.log(err)//failure callback(if any one request got rejected)
    });

   /*---------------------------------------------------------------*/

}).catch(function (err) {})
Siva Kannan
fuente
1
¿Por qué crea una cadena de promesas anidadas para la operación después de la conexión? Por qué no:MongoClient.connect(uri).then(client => client.db("db").collection("users").find()).then(data => console.log(data)).catch(err => console.log(err));
SerG
Esto sería mejor con enlaces a la documentación
mikemaccana
Notación más corta para la captura: .catch (console.log)
Benjam
2

ADVERTENCIA Editar:

Como señaló John Culviner, esta respuesta está en desuso. Utilice el controlador, viene con promesas OOTB.


Si elige usar bluebird como biblioteca de promesas, puede usar la promisifyAll()función bluebirds en MongoClient:

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

var url = 'mongodb://localhost:27017/example';

MongoClient.connectAsync(url).then(function (db) {
    console.log(db);
}).catch(function(err){
    //handle error
    console.log(err);
});
Simon Z.
fuente
6
El controlador MongoDB ya tiene promesas (si desea bluebird, puede especificarlo en las opciones o como lo adjunto a global.Promise) ¡NO HAGA ESTO!
John Culviner
2

Sé que llego un poco tarde a la fiesta, pero me gustaría compartir un ejemplo con ES6.

const config = require('config');
const MongoClient = require('mongodb').MongoClient;

var _connection;
var _db;

const closeConnection = () => {
  _connection.close();
}

/**
 * Connects to mongodb using config/config.js
 * @returns Promise<Db> mongo Db instance
 */
const getDbConnection = async () => {
  if (_db) {
    return _db;
  }
  console.log('trying to connect');
  const mongoClient = new MongoClient(config.mongodb.url, { useNewUrlParser: true });
  _connection = await mongoClient.connect();
  _db = _connection.db(config.mongodb.databaseName);
  return _db;
}

module.exports = { getDbConnection, closeConnection };

Entro un poco más en detalle aquí si quieres echar un vistazo:

https://medium.com/swlh/how-to-connect-to-mongodb-using-a-promise-on-node-js-59dd6c4d44a7

Alex García
fuente
muy agradable. Simplemente cambiaría el nombre de la función getDbConnection porque no devuelve la conexión. Devuelve _db. :)
kroiz
1

Puede utilizar un paquete alternativo, como mongodb-promisepromisificar la mongodbAPI del paquete manualmente creando sus propias promesas a su alrededor o mediante un paquete de utilidad de promesa comobluebird.promisify

Markusthoemmes
fuente
El controlador MongoDB ya tiene promesas (si desea bluebird, puede especificarlo en las opciones o como lo adjunto a global.Promise) ¡NO HAGA ESTO!
John Culviner
1

Solución de trabajo con MongoDB versión> 3.0

var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";


open = (url) => {
    return new Promise((resolve,reject) => {
        MongoClient.connect(url, (err,client) => { //Use "client" insted of "db" in the new MongoDB version
            if (err) {
                reject(err)
            } else {
                resolve({
                    client
                });
            };
        });
    });
};

create = (client) => {
    return new Promise((resolve,reject) => {
        db = client.db("myFirstCollection"); //Get the "db" variable from "client"
        db.collection("myFirstCollection").insertOne({
            name: 'firstObjectName',
            location: 'London'
            }, (err,result)=> {
                if(err){reject(err)}
                else {
                    resolve({
                        id: result.ops[0]._id, //Add more variables if you want
                        client
                    });
                }

            });
    });
};

close = (client) => {
    return new Promise((resolve,reject) => {
        resolve(client.close());
    })

};

open(url)
    .then((c) => {
        clientvar = c.client;
        return create(clientvar)
    }).then((i) => {
        idvar= i.id;
        console.log('New Object ID:',idvar) // Print the ID of the newly created object
        cvar = i.client
        return close(cvar)
    }).catch((err) => {
        console.log(err)
    })
Dimitar Zafirov
fuente
0

Necesita crear una promesa que se conecte a Mongo.

A continuación, defina su función que utiliza esta promesa: myPromise.then(...).

Por ejemplo:

function getFromMongo(cb) {
    connectingDb.then(function(db) {

       db.collection(coll).find().toArray(function (err,result){
           cb(result);
       });

    });
}

aquí está el código completo:

http://jsfiddle.net/t5hdjejg/

Maria Maldini
fuente
El controlador MongoDB ya tiene promesas (si desea bluebird, puede especificarlo en las opciones o como lo adjunto a global.Promise) ¡NO HAGA ESTO!
John Culviner
@JohnCulviner por lo que puedo decir, .find no devuelve una promesa? Algunos métodos lo hacen - .count () en un cursor lo hace, por ejemplo - pero db.mycoll.find ({}). Then is undefined?
sil
@sil db.get ("colección"). find ({algo: "a"}). then (). catch (); funciona para mí
Rafique Mohammed
0

Aquí hay una línea para abrir la conexión.

export const openConnection = async ()  =>
     await MongoClient.connect('mongodb://localhost:27017/staticback')

y llámalo así

const login = async () => 
const client = await openConnection()
mella
fuente
-1

No parece que el método de conexión tenga una interfaz de promesa definida

http://mongodb.github.io/node-mongodb-native/2.1/tutorials/connect/

siempre puede implementarlo usted mismo en la biblioteca de conectores de Mongodb, pero probablemente sea más complicado de lo que está buscando.

Si realmente necesita trabajar con promesas, siempre puede usar el polyfill de promesas de ES6:

https://github.com/stefanpenner/es6-promise

y envuelva su código de conexión con eso. Algo como

var MongoClient = require('mongodb').MongoClient;
var Promise = require('es6-promise').Promise;

var url = 'mongodb://localhost:27017/example';

var promise = new Promise(function(resolve, reject){
    MongoClient.connect(url, function (err, db) {
        if(err) reject(err);
        resolve(db);
    });        
});

promise.then(<resolution code>);
andrewkodes bueno
fuente