【问题标题】:async/await is not working for mongo DB queriesasync/await 不适用于 mongoDB 查询
【发布时间】:2019-05-30 17:13:10
【问题描述】:

工作案例:

当我们调用一个异步函数并且该函数返回一个 promise resolve() 时,async await 工作正常

不工作的情况:

async await 不适用于 mongo DB 查询

试过 then(),异步/等待

我有 2 个 JS 文件。

在 one.js 文件中,我正在导入 functionone.js 中的函数

工作案例:

当 one.js 看起来像时

var functiononestatus = transactions.functionone(req.session.email).then((came) => {
  console.log(came); // getting `need to be done at first` message
  console.log("exec next")
});

functionone.js 的样子

module.exports.functionone = functionone;

async function functionone(email) {
  return await new Promise((resolve, reject) => {
    resolve('need to be done at first')
  });
});

NOT WORKING CASE(当需要执行 mongo db 查询时):

当 one.js 看起来像时

var functiononestatus = transactions.functionone(req.session.email).then((came) => {
  console.log(came); // getting undefined
  console.log("exec next")
});

functionone.js 的样子

module.exports.functionone = functionone;

async function functionone(email) {

  //mongo starts
  var collection = await connection.get().collection('allinonestores');
  await collection.find({
    "email": email
  }).toArray(async function(err, wallcheck) {
    return await new Promise((resolve, reject) => {
      resolve(wallcheck[0])
    });
  });

【问题讨论】:

  • 第二个,functionone 没有返回任何东西,因此undefined
  • 实际上我们在wallcheck[0] 中获取值(在第二个函数中)但是code one.js 变得未定义,尽管我们在wallcheck[0] 中有值
  • 是的,因为您的 functionone 没有返回任何内容。
  • 我明白,但问题是你?
  • 它没有返回任何内容,因为函数中没有 return 语句。尝试使用 return 返回 Promise。

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


【解决方案1】:

快速澄清:

  1. .collection('name') 返回一个 Collection 实例,而不是 Promise,因此不需要 await
  2. toArray() 在两种模式下运行:要么在提供函数时使用回调,要么在未提供回调函数时返回 Promise。

在提供回调函数时,您实际上期望 toArray() 的 Promise 结果,导致 undefined,因为回调优先且不返回任何承诺,因为 toArray() 的双重操作模式。

另外,toArray(callback) 不会将 async 函数作为回调。

你的代码应该是这样的,用于检索一个集合:

const client = await MongoClient.connect('your mongodb url');
const db = client.db('your database name'); // No await here, because it returns a Db instance.
const collection = db.collection('allinonestores'); // No await here, because it returns a Collection instance.

然后,获取结果的代码:

const db = <get db somehow>;

// You could even ditch the "async" keyword here,
// because you do not do/need any awaits inside the function.
// toArray() without a callback function argument already returns a promise.
async function functionOne(email) {

  // Returns a Collection instance, not a Promise, so no need for await.
  const collection = db.collection('allinonestore');

  // Without a callback, toArray() returns a Promise.
  // Because our functionOne is an "async" function, you do not need "await" for the return value.
  return collection.find({"email": email}).toArray();
}

和代码替代,使用回调:

const db = <get db somehow>;

// You could even ditch the "async" keyword here,
// because you do not do/need any awaits inside the function.
// You're forced to return a new Promise, in order to wrap the callback
// handling inside it
async function functionOne(email) {

  // Returns a Collection instance, not a Promise, so no need for await.
  const collection = db.collection('allinonestore');

  // We need to create the promise outside the callback here.
  return new Promise((resolve, reject) => {
    db.find({"email": email}).toArray(function toArrayCallback(err, documents) {
       if (!err) {
         // No error occurred, so we can solve the promise now.
         resolve(documents);
       } else {
         // Failed to execute the find query OR fetching results as array someway failed.
         // Reject the promise.
         reject(err);
       }
    });
  });
}

【讨论】:

  • [...]Also, toArray(callback) does not take an async function as callback.[...] 有点误导,对于toArray,函数是否为async 并不重要(因为它不使用返回值),所以它是完美的如果您想/需要在该函数中使用await,可以将async 函数传递给toArray
  • 确实,回调执行不会禁止异步函数。但是,在调用者不处理承诺返回值的情况下编写异步函数是一种不好的做法,因为除了性能成本之外,它还会造成混淆,您可以在其中返回承诺/执行等待,这是错误的:异步回调永远不会在这种情况下等待,并且其中的所有承诺都将在回调已经执行后解决。
  • 这不是真的,否则您应该将您在回调函数中执行的任何异步操作视为不使用该异步操作的结果作为结果的错误做法。如果你例如将 express js 用于任何其他涉及路由的库,那么您将拥有类似 app.get('/path', (req, res, next) =&gt; res.send('ok')) 的内容。所以现在你可能需要在其中做一些异步操作,然后你可以肯定写app.get('/path', async (req, res, next) =&gt; try{ res.send(await req.db.find()) } catch( err ) {next(err)}) 即使app.get 不使用回调返回的 Promise。
  • 我的实际问题是,如果文档为 != 空否则失败消息,我需要返回成功消息,但是当返回消息在问题中提到的 mongo 查询内时,我会变得不确定。跨度>
  • @t.niese Mihai Potra 在回调只执行一次的情况下绝对正确,应该为这种情况创建一个new Promise 而不是嵌套async functions。即使是您的明确示例,我也不会考虑好的风格,因为它使try/catch 成为必要。我是easier to writeapp.get('/path', promiseWrapper(async (req, res) =&gt; { res.send(await req.db.find()); }));
【解决方案2】:

注意:首先我真的要感谢@mihai Potra 的最佳答案。

我们来了

案例一:

如果是像mihai提到的那样需要查找文档并从MongoDb返回的功能,下面的答案是超级酷

const db = <get db somehow>;
async function functionOne(email) {
  const collection = db.collection('allinonestore');
  return collection.find({"email": email}).toArray();
}

案例2:

如果有嵌套函数每次都需要在下面返回值,那么据我所知是最好的

-每个函数都不需要 async/await 关键字,或者不需要 then()

function one(<parameter>) {
return new Promise(function(resolve, reject) {
const collection = connection.get().collection('<collection_name>');
const docs = collection.find({"Key": Value_fromFunction}).toArray( function (err, result) {
resolve(result[0]);
});

就是这样,在需要时使用解析回调。

【讨论】:

    猜你喜欢
    • 2022-01-11
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2019-10-24
    • 2018-07-10
    • 2021-06-18
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多