Why even after using async await for multiple calls still got empty response?

ε祈祈猫儿з 提交于 2019-12-24 01:15:36

问题


Here is simple node route in which calling an asynchronous api.

What needed is to return data after the looping. But It is returning blank object.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  array.map(async(d) => {
    const venue = await Venue.find({ "category": { "$in": [d] }})
    data[d] = venue
  })
  return data
} catch(err) {
  throw err
}

Please help me to achieve this


回答1:


There is a better way to get the desired result with MongoDB and no need to loop, use the aggregation framework where you can run the following pipeline which uses $facet as

try {
    const array = ["brunch", "lunch", "crunch"]
    const facet = array.reduce((acc, cur) => {
        acc[cur] = [{ "$match": { "category": cur } }]
        return acc
    }, {})
    const pipeline = [
        { "$match": { "category": { "$in": array } } },
        { "$facet": facet }
    ]
    const results = await Venue.aggregate(pipeline).exec()
    const data = results[0]

    return data
} catch(err) {
    throw err
}

You can also group the documents by the category key and $push the documents per group and then convert into keys of a document in a $replaceRoot with $arrayToObject

try {
    const array = ["brunch", "lunch", "crunch"]
    const pipeline = [
        { "$match": { "category": { "$in": array } } },
        { "$group": { 
            "_id": "$category",
            "data": { "$push": "$$ROOT" }
        } },
        { "$group": {
            "_id": null,
            "venues": {
                "$push": {
                    "k": "$_id",
                    "v": "$data"
                }
            } 
        } },
        { "$replaceRoot": {
            "newRoot": { "$arrayToObject": "$venues" }
        } }
    ]
    const results = await Venue.aggregate(pipeline).exec()
    const data = results[0]

    return data
} catch(err) {
    throw err
}



回答2:


Although @chridam approach is quite unique and maybe more efficient, in case you want to stick with a loop.

There are two approaches. You want all your operation to be run in parallel or series.

If parallel, you will have to use Promise.all.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  await Promise.all(array.map(async(d) => {
    data[d] = await Venue.find({ "category": { "$in": [d] }})
  }))
  return data
} catch(err) {
  throw err
}

If series, you will have to use simple for loop.

array.map(async(d) => {}) is making the internal db call asynchronous and not waiting for operation. normal for loop will be synchronous.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  for (d of array) {
    data[d] = await Venue.find({ "category": { "$in": [d] }})
  }
  return data
} catch(err) {
  throw err
}



回答3:


Problem is the way you are using async-await. It's inside a Array.prototype.map which made .map function asynchronous and thus main thread never waits for loop to complete and move forward to next statement and returned data which is just {}.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {};

  // here's the issue async is callback function to map, due to which never waited for map function to finished.
  array.map( async(d) => {
    const venue = await Venue.find({ "category": { "$in": [d] }})
    data[d] = venue;
  });

  return data;
} catch(err) {
  throw err
}

Change code to this:

(async function () {
    try {
      const array = ["brunch", "lunch", "crunch"]
      const data = {};

      array.map( d => {
        const venue = await Venue.find({ "category": { "$in": [d] }})
        data[d] = venue;
      });

      return data;

    }
    catch(err) {
      throw err
    }
})();

What you did is something similar to this

function main () {
    return new Promise ( resolve => {
        setTimeout( () => {
            console.log("First");
            resolve(true);
        },5000 );
    });
}

(async function () {
    await main();

    console.log("Second")
})();

console.log("Third");
// Third
// First
// Second


来源:https://stackoverflow.com/questions/52534679/why-even-after-using-async-await-for-multiple-calls-still-got-empty-response

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!