Node.js mongodb驱动程序async / await查询

时间:2017-11-18 20:03:51

标签: javascript node.js mongodb mongoose async-await

我有一个使用mongodb本机驱动程序的node.js应用程序。 在使用节点v8.9.1将我的应用程序代码迁移到async / await的过程中,我正在努力为mongodb查询找到一种优雅的方式。 mongodb驱动程序的主要问题是,所有查询都使用回调,其中promises函数对于异步方法是必需的。

备选方案:

  • mongoose - 不推荐使用promises查询,它强制使用Schema模型,这对我的应用来说有点开销。
  • mongoist - 据称很棒,因为它是以async / await构建并完全承诺的,但SSL连接到mongodb和文档不佳的错误 - 让我远离这个解决方案。

我成功实现的唯一解决方法是使用 callback-promise npm包将mongodb驱动程序API转换为完全承诺。

任何有关优雅高性能方式的新想法?

11 个答案:

答案 0 :(得分:25)

编辑:' mongodb'的 3.x版

根据mongoDB ES6 future  你可以用这种方式;

let MongoClient = require('mongodb').MongoClient;
const connectionString = 'mongodb://localhost:27017';

    (async () => {
        let client = await MongoClient.connect(connectionString,
            { useNewUrlParser: true });

        let db = client.db('dbName');
        try {
           const res = await db.collection("collectionName").updateOne({ 
               "someKey": someValue
           }, { $set: someObj }, { upsert: true });

           console.log(`res => ${JSON.stringify(res)}`);
        }
        finally {
            client.close();
        }
    })()
        .catch(err => console.error(err));

答案 1 :(得分:20)

感谢。与ES6合作很好:

const middleWare = require('middleWare');
const MONGO = require('mongodb').MongoClient;

router.get('/', middleWare(async (req, res, next) => {
    const db = await MONGO.connect(url);
    const MyCollection = db.collection('MyCollection');
    const result = await MyCollection.find(query).toArray();
    res.send(result);
}))

答案 2 :(得分:10)

这是我发现与Mongo3和async / await兼容的最小代码段。 享受吧!

module.exports = {
  myFunction: async (query) => {
    let db, client;
    try {
      client = await MongoClient.connect(process.env.MONGODB_CONNECTION_STRING, { useNewUrlParser: true });
      db = client.db(dbName);
      return await db.collection(collectionName).find(query).toArray();
    } finally {
      client.close();
    }
  }
}

答案 3 :(得分:5)

由于所有答案都缺少一些内容(捕获块,请检查客户端是否不是null),所以我提供了自己的解决方案。已在Mongo服务器v4.0.7和Node JS驱动程序3.2.2中进行了测试。

请注意,该示例是一个控制台程序,我们在finally块中关闭了与服务器的连接。在Web应用程序中,连接被重用。 参见Node Mongo docs。另外,错误是使用Winston或Morgan等库记录的,而不是控制台记录的。

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

const url = 'mongodb://localhost:27017';

async function findOne() {

    const client = await MongoClient.connect(url, { useNewUrlParser: true })
        .catch(err => { console.log(err); });

    if (!client) {
        return;
    }

    try {

        const db = client.db("testdb");

        let collection = db.collection('cars');

        let query = { name: 'Volkswagen' }

        let res = await collection.findOne(query);

        console.log(res);

    } catch (err) {

        console.log(err);
    } finally {

        client.close();
    }
}

findOne();

答案 4 :(得分:4)

我将此作为答案发布,因为我无法对Ido Lev's answer发表评论。一旦我达到50点,我就会动作。

不要忘记关闭数据库连接。否则,由于开放连接太多(一周前发生在我身上),您的应用程序可能无法连接到数据库。

您的查询可能成功或失败,因此在finally - 块中关闭连接是有意义的。

const db = await MongoClient.connect(url);
try {
    const stuff = await db.collection("Stuff").find({});
    // Do something with the result of the query
} finally {
    db.close();
}

更新:这似乎也没有解决我的问题。有人说你甚至不需要手动关闭连接。如果可能的话,在您的应用程序中重用您的连接似乎是最好的。

答案 5 :(得分:3)

如果你没有通过回调,mongodb客户端会返回一个承诺。

  

官方MongoDB Node.js驱动程序提供基于回调和基于Promised的MongoDB交互,允许应用程序充分利用ES6中的新功能

来自官方 docs

答案 6 :(得分:3)

  

猫鼬使用异步/等待查找查询

不要在异步/等待的情况下使用mongoose.connect

    var router = require("express").Router()
    var mongoose = require("mongoose")
var await = require("await")
var async = require("async")

    var mongoUrl = "mongodb://localhost:27017/ekaushalnsdc"

    router.get("/async/await/find",async(req, res,  next) => {
      try {
        var db =  await mongoose.createConnection(mongoUrl)
          var colName = db.collection('collectionName')
        var result  = await colName.find({}).toArray()
        res.json(result)
    }catch(ex) {
       res.json(ex.message)
    }
    })

答案 7 :(得分:2)

如果你想使用游标而不卸载到Array,你不能使用await和find()或aggregate()函数,那么你必须使用代码:

Usas的UPD: 对于一般情况,使用toArray()的答案就足够了。

但是当涉及大量文档集时,使用toArray()会超出可用RAM。因此,在这些情况下,“高性能”解决方案不得使用toArray()。

对于这些情况,你可以使用MongoDB流,它运行良好,但比使用流更简单:

Won't Fix

答案 8 :(得分:1)

(基于Pax Beach的回答。它已被否决,我想添加一条评论来解释为什么在某些情况下Pat的回答是最好的。我没有足够的代表来添加评论。)

对于一般情况,使用toArray()的答案就足够了。

但是当涉及到巨大的文档集合时,使用toArray()会超出可用的RAM。因此,在这些情况下的“高性能”解决方案一定不能使用toArray()。

在这种情况下,您可以使用MongoDB流,效果很好,但比使用流更简单:

org.hibernate.type.LocalDateType - Maps a java.time.LocalDate to a Oracle DATE    
org.hibernate.type.LocalDateTimeType - Maps a java.time.LocalDateTime to a Oracle TIMESTAMP

答案 9 :(得分:1)

我是来这里寻求async/await解决方案的,但我真的不喜欢任何答案,所以我想出了以下代码段。

我正在使用本机驱动程序,并且效果很好。我发现它比for循环更具可读性:

const cursor = await db.collection('myCollection').find({});

while (await cursor.hasNext()) {
  const doc = await cursor.next();
  // do whatever, ex.
  console.log(doc);
};

toArray()方法也可以,但是-如之前所指出的-您必须确保您永远不会获得占用内存的大型结果集。

答案 10 :(得分:0)

我正在尝试使用mongojs从mongodb获取数据并显示在graphiql服务器中。我用了诺言,终于做到了。

async resolve(parent,args){
                function getdata(){
                return new Promise(function(resolve,reject){
                    var o_id = ObjectId(args.id);
                    var obj = {_id:o_id}
                    db.book.find(obj,(err,data) => {
                        if(err){
                            console.log(err);
                            reject("error in sending the book data");
                            }
                        else{
                                if(data.length>0){
                                   resolve(data);
                                }else{reject("data length is ! > 0")}
                        }
                    });
                })
                }
                async function calldata(){
                    var dataNew = await getdata().then(function(returnedData){
                        return returnedData;
                    }).catch(function(errorinpassing){
                        console.log(errorinpassing);
                    })
                    return dataNew
                }
                var hello = await calldata()
                if(hello.length>0){
                    return hello[0]
                }
            }