Javascript Node.js mongodb 驱动程序异步/等待查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47370487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:49:30  来源:igfitidea点击:

Node.js mongodb driver async/await queries

javascriptnode.jsmongodbmongooseasync-await

提问by Ido Lev

I have a node.js application using mongodb native driver. In the process of migrating my application code to async/await using node v8.9.1, I am struggling to find an elegant way for the mongodb queries. The major problem with mongodb driver is, that all queries are using callbacks where promises functions are mandatory for the async methods.

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

Alternatives:

备择方案:

  • mongoose- promises queries deprecated and it forces using Schema model which is a little overhead for my app.
  • mongoist- allegedly great, since it built with async/await in mind and fully promise, but errors with SSL connection to mongodb and poor documentations- drew me away from this solution.
  • mongoose- 承诺查询已弃用,它强制使用 Schema 模型,这对我的应用程序来说是一个小开销。
  • mongoist- 据称很棒,因为它在构建时考虑了 async/await 并完全承诺,但是与 mongodb 的 SSL 连接错误和糟糕的文档 - 让我远离了这个解决方案。

The only workaround I succeeded to implement in an elegant way is using callback-promisenpm package to convert mongodb driver API to fully promise.

我以优雅的方式成功实现的唯一解决方法是使用回调承诺npm 包将 mongodb 驱动程序 API 转换为完全承诺。

Any fresh ideas for an elegant high performance way?

对于优雅的高性能方式有什么新鲜的想法吗?

采纳答案by Jan Bodnar

Since all answers are missing some bits (catch blocks, checking that client is not null) I came with my own solution. Tested with Mongo server v4.0.7 and Node JS driver 3.2.2.

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

Note that the example is a console program, where we close the connection to the server in the finallyblock. In a web application, the connections are reused. See Node Mongo docs. Also, the errors are logged with libraries such as Winston or Morgan and not console logged.

请注意,该示例是一个控制台程序,我们在该程序finally块中关闭了与服务器的连接。在 Web 应用程序中,连接被重用。请参阅Node Mongo 文档。此外,错误是使用 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();

回答by Serhat Ates

Edit: 'mongodb' v3.x

编辑:'mongodb' v3.x

according to mongoDB ES6 futureyou can use this way;

根据mongoDB ES6 未来,您可以使用这种方式;

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

回答by Ido Lev

Thanks. Working great with ES6:

谢谢。与 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);
}))

回答by Sovattha Sok

This is the smallest piece of code I found that is compatible with Mongo3 and async/await. Enjoy!

这是我发现的与 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();
    }
  }
}

回答by Surya

If u don't pass a callback, mongodb client returns a promise.

如果你不传递回调,mongodb 客户端会返回一个承诺。

The official MongoDB Node.js driver provides both callback based as well as Promised based interaction with MongoDB allowing applications to take full advantage of the new features in ES6

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

From the official docs

来自官方 文档

回答by Pax Beach

If you want to work with cursor without unloading to Array, you can't use await with find() or aggregate() functions, then you have to use the code:

如果您想在不卸载到数组的情况下使用游标,则不能将 await 与 find() 或 aggregate() 函数一起使用,那么您必须使用以下代码:

UPD by Usas:For the general case, the answers using toArray() are sufficient.

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

But when huge document collections are involved, using toArray() would exceed available RAM. Thus a "high performance" solution in those situations must not use toArray().

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

For those cases, you can use MongoDB streams, which works well, but even simpler than using streams is to:

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

const cursor = db.collection('name').aggregate(
    [
        {
            "$match": {code: 10}
        },
        {
          "$count": "count"
        }
    ],
    {
        "allowDiskUse": false
    }
)

for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
    console.log('aggregate:', doc.count);
}

回答by 0xC0DEBA5E

I'm posting this as an answer because I can't comment on Ido Lev's answer. I will move this as soon as I have reached 50 reputation.

我将此作为答案发布,因为我无法评论Ido Lev 的答案。一旦我达到50声望,我就会移动这个。

Don't forget to close the db connection. Otherwise it's possible that your application can't connect to the db because of too many open connections (happened to me a week ago).

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

Your query may succeed or fail, so it makes sense to close the connection in a finally-block.

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

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

Update: It seems that this also didn't fix my problem. Some people say that you don't even need to close the connection manually. It seems like it's best to reuse your connection across you application if possible.

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

回答by muthukumar helius

mongoose find Query Using async/await

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

dont Use mongoose.connectin case of async/await

不要mongoose.connect在 async/await 的情况下使用

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

回答by Usas

(Based on Pax Beach's answer. It had been downvoted, and I wanted to add a comment explaining why in some situations, Pat's answer is the best. I don't have enough rep to add comments.)

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

For the general case, the answers using toArray() are sufficient.

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

But when hugedocument collections are involved, using toArray() would exceed available RAM. Thus a "high performance" solution in those situations must not use toArray().

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

For those cases, you can use MongoDB streams, which works well, but even simpler than using streams is to:

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

const cursor = db.collection('someCollection').find({})
for (let doc = await cursor.next(); doc; doc = await cursor.next()) {
    // Process the document.
}

回答by Vedha Krishhna

I am trying to get the data from mongodb using mongojs and display in graphiql server. I have used promises and got it finally.

我正在尝试使用 mongojs 从 mongodb 获取数据并显示在 graphiql 服务器中。我已经使用了 Promise 并最终得到了它。

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]
                }
            }