嵌套异步/等待猫鼬查询

时间:2020-09-10 16:53:30

标签: node.js mongoose async-await

我有一个async函数,需要返回一个user_ids数组。我的代码就像:

async function getUserIds(option) {
  let user_ids = [];

  if (option === 'test') {
    const departments = await Departments.find({}).exec()
      .catch(() => console.log('ERROR');

    console.log('BEFORE LOOP');

    await departments.forEach(async(dpt) => {
      const pop = await Populations.findOne({_id: dpt.id}) 
        .catch(() => console.log('ERROR');

      console.log('work...');

      if (pop && (pop.max > pop.min)) {    
        const _users = await User.find({_id: {$in: pop.ids}}).exec()
          .catch(() => console.log("ERROR");

        user_ids = user_ids.concat(_users.map((u) => u._id));
        console.log('finished work...');
      }
    });

    return user_ids;
}

async function main() {
    let user_ids = await getUserIds('test');
    console.log(user_ids);
}

现在,这总是返回一个空数组[],我可以以异步方式看到控制台日志:

BEFORE LOOP
[]   --> the return 
work...
work...
work...
work...
work...
work...
finished work...
finished work...
work...
finished work...
work...
finished work...
finished work...

我猜这行await departments.forEach(async(dpt) => {并不是真的"awaiting",所以我该怎么办,我做错了什么?

2 个答案:

答案 0 :(得分:2)

async / await是使用Promise的一种糖方式。

async就像new Promise(),而await就像.then()

使用Promise.all()等到所有Promise的决心都解决后再继续。

在这种情况下,您应该使用Array.prototype.map()而不是Array.prototype.forEach()forEach()返回undefined,您正在使用await.map()将返回一个Promise数组:

// Using .map()
departments = [ Promise, Promise, Promise ] // await till all Promise resolves to go foward.

// Using .forEach()
departments = 'undefined' // nothing to await for.

await Promise.all(
        departments.map(async(dpt) => {
            const pop = await Populations.findOne({_id: dpt.id})
                .catch(() => console.log('ERROR');

            console.log('work...');

            if (pop && (pop.max > pop.min)) {    
                const _users = await User.find({_id: {$in: pop.ids}}).exec()
                    .catch(() => console.log("ERROR");

                user_ids = user_ids.concat(_users.map((u) => u._id));
                
                console.log('finished work...');
            }
       })
);

答案 1 :(得分:1)

在从函数返回结果之前,您应该等待部门的承诺。第forEach行在您的情况下不起作用,请用mapfor of

代替

map为例

...
const promises = departments.map(async(dpt) => {
  const pop = await Populations.findOne({_id: dpt.id}) 
    .catch(() => console.log('ERROR');

  console.log('work...');

  if (pop && (pop.max > pop.min)) {    
    const _users = await User.find({_id: {$in: pop.ids}}).exec()
      .catch(() => console.log("ERROR");

    user_ids = user_ids.concat(_users.map((u) => u._id));
    console.log('finished work...');
  }
});

await Promise.all(promises)

return user_ids