【问题标题】:How to use MongoDB with promises in Node.js?如何在 Node.js 中使用带有 Promise 的 MongoDB?
【发布时间】:2016-06-19 21:03:57
【问题描述】:

我一直在尝试发现如何将 MongoDB 与 Node.js 一起使用,在文档中似乎建议的方法是使用回调。现在,我知道这只是一个偏好问题,但我更喜欢使用 Promise。

问题是我没有找到如何将它们与 MongoDB 一起使用。确实,我尝试了以下方法:

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

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

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

结果是undefined。在那种情况下,这似乎不是这样做的方法。

有什么方法可以在 Node 中使用带有 promises 而不是回调的 mongo db?

【问题讨论】:

标签: javascript node.js mongodb


【解决方案1】:

你的方法几乎是正确的,只是你的论点中有一个小错误

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

【讨论】:

  • 没错! MongoDB Node.js 驱动程序 2.x "Returns: Promise if no callback pass" i.a.通过MongoClient.connect。如果你的 node.js MongoClient.connect 的 promiseLibrary 选项提供一个 ES6 兼容的 Promise 实现。
  • 根据一些测试,如果你连接到 URL mongodb//localhost:27017(没有指定数据库)你会得到一个 mongoclient,所以你需要调用mongoclient.db('example')。见mongodb.github.io/node-mongodb-native/api-generated/…
【解决方案2】:

你也可以做 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
}

【讨论】:

  • 我现在可以亲吻你的脸。这是我在几个小时内找到的最简单、最好的答案。
  • 这只是最简单、最新鲜、最完整和最新的答案。非常感谢。
  • 对我来说,这引发了错误“无法使用已结束的会话”。这是因为 result.toArray() 也返回了一个 Promise。所以你必须使用“await result.toArray()”
【解决方案3】:

由于上面的答案都没有提到如何在没有 bluebird 或 q 或任何其他花哨的库的情况下做到这一点,所以让我在这上面加上我的 2 美分。

这是使用原生 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;

我将我的 open() 方法定义为返回承诺的方法。要执行插入,下面是我的代码 sn-p

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

希望对您有所帮助。如果您有任何改进的建议,请告诉我,因为我愿意改进自己:)

【讨论】:

  • 你将一个承诺包装在另一个承诺中。 MongoClient 方法已经返回了一个 Promise,不需要再次包装它。这是一个典型的反承诺模式。
  • 几个月后出现,但@Green 在原始帖子使用 mongodb.MongoClient 的本机承诺支持并且没有多余的承诺库后 20 分钟的回答。
  • 这应该是正确答案,因为它不依赖任何第三方承诺库。
  • @westor 你将如何从 open() 方法返回一个 Promise 而不将它包装在新的 Promise 中?我认为这是唯一的方法。
  • @AbhishekNalin MongoDB 连接方法(至少在较新版本中)返回一个承诺。因此,您可以简单地编写“mongoClient.connect(url).then(...)”,或者在此打开方法中,您将返回 mongoClient.connect(url)。您可以摆脱回调。错误情况被这里的最后一个 catch 捕获。
【解决方案4】:

这是如何在 Node.js 中将 MongoDB 与 Promise 一起使用?

的一般答案

如果省略回调参数,mongodb 将返回一个承诺

转换为 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)
        });
    }
})

转换为 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) {})

如果您需要处理多个请求

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

【讨论】:

  • 为什么要创建嵌套promise链用于连接后的操作?为什么不:MongoClient.connect(uri).then(client =&gt; client.db("db").collection("users").find()).then(data =&gt; console.log(data)).catch(err =&gt; console.log(err));
  • 如果有文档链接会更好
  • catch 的短符号:.catch(console.log)
【解决方案5】:

警告编辑:

正如 John Culviner 所指出的,此答案已被弃用。使用驱动,自带承诺OOTB。


如果你选择使用 bluebird 作为 promise 库,你可以在 MongoClient 上使用 bluebirds promisifyAll() 函数:

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

【讨论】:

  • MongoDB 驱动程序已经有了承诺(如果你想要 bluebird,你可以在选项中指定,或者像我一样将它附加到 global.Promise)不要这样做!
【解决方案6】:

我知道我参加聚会有点晚了,但我想分享一个使用 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 };

如果你想看一下,我会在这里更详细地介绍:

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

【讨论】:

  • 非常好。我只是重命名函数 getDbConnection 因为它不返回连接。它返回_db。 :)
【解决方案7】:

这是一个打开连接的单列

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

然后这样称呼它

const login = async () => 
const client = await openConnection()

【讨论】:

    【解决方案8】:

    您可以使用替代包,例如 mongodb-promise 或通过围绕它构建自己的 Promise 或通过像 bluebird.promisify 这样的 Promise 实用程序包手动承诺 mongodb 包 API

    【讨论】:

    • MongoDB 驱动程序已经有了承诺(如果你想要 bluebird,你可以在选项中指定,或者像我一样将它附加到 global.Promise)不要这样做!
    【解决方案9】:

    使用 MongoDB 版本 > 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)
        })
    

    【讨论】:

      【解决方案10】:

      这是基于@pirateApp's 的回答。

      
      const open = (dbName, collectionName) => {
        const URI = process.env.MONGO_URI;
        return new Promise((resolve, reject) => {
          let savedConn = null;
          MongoClient.connect(URI, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
          })
            .then((conn) => {
              savedConn = conn;
              return conn.db(dbName).collection(collectionName);
            })
            .then((db) => {
              resolve({ db, savedConn });
            })
            .catch((err) => reject(err));
        });
      };
      
      

      【讨论】:

      • 关闭连接怎么样?
      【解决方案11】:

      你需要创建一个连接到 Mongo 的 Promise。

      然后,定义使用此承诺的函数:myPromise.then(...)

      例如:

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

      这里是完整的代码:

      http://jsfiddle.net/t5hdjejg/

      【讨论】:

      • MongoDB 驱动程序已经有了承诺(如果你想要 bluebird,你可以在选项中指定,或者像我一样将它附加到 global.Promise)不要这样做!
      • @JohnCulviner 据我所知, .find 不返回承诺?有些方法可以——例如,游标上的 .count() 可以——但是 db.mycoll.find({}).then 是未定义的?
      • @sil db.get("collection").find({something:"a"}).then().catch();为我工作
      【解决方案12】:

      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
      }

      【讨论】:

        【解决方案13】:

        connect 方法似乎没有定义 promise 接口

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

        您始终可以在 Mongodb 连接器库中自己实现它,但这可能比您想要的要复杂。

        如果你真的需要使用 Promise,你总是可以使用 ES6 Promise polyfill:

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

        并用它来包装你的连接代码。类似的东西

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

        【讨论】:

          猜你喜欢
          • 2013-10-07
          • 2018-06-16
          • 1970-01-01
          • 1970-01-01
          • 2014-04-16
          • 2016-05-04
          • 1970-01-01
          • 2014-05-05
          • 1970-01-01
          相关资源
          最近更新 更多