NodeJS, ожидание работы с БД

Мне нужно добиться того, чтобы ответ от бекенда на фронт приходил только после того, как закончится добавление данных в БД. После получения ответа, фронт посылает запрос в БД (и там должна быть эта информация).

Ни один из кучи вариантов с Промисами не помог, судя по всему, я что-то делаю не так.

Нужно добиться того, чтобы res.send срабатывал только после того, как выполнится добавление данных в БД в модуле bruteForceMatches

router.post('/summoner', async (req, res) => {
    const name = encodeURI(req.body.summoner);
    const region = (req.body.region).toUpperCase();

    const profileURL = `https://${region}.api.riotgames.com/lol/summoner/v4/summoners/by-name/${name}`;
    const summonerInfo = await getData(profileURL, collectSummonerInfo, region);

    const leagueURL = `https://${region}.api.riotgames.com/lol/league/v4/entries/by-summoner/${summonerInfo.sumId}`;
    const rankedInfo = await getData(leagueURL, collectRankedInfo);

    const puuId = summonerInfo.puuId;
    const matchList = [];
    let start = 0;
    const matchListURL = `https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/${puuId}/ids?start=${start}&count=5`;
    matchList.push(...await getData(matchListURL));

    const result = await bruteForceMatches(matchList);
    
    if (result === 'hey') {
        console.log(4, result);
        res.send(JSON.stringify({...summonerInfo, ...rankedInfo}));
    }
})

Так выглядит модуль bruteForceMatches

module.exports = async (matchList) => {
    const answers = [];

    const func = () => {
        return new Promise((resolve, reject) => {
            for (let matchId of matchList) {
                match.findOne({matchId: matchId}, async (err, doc) => {
                    if (!doc) {
                        const matchURL = `https://europe.api.riotgames.com/lol/match/v5/matches/${matchId}`;
                        const matchInfo = await getData(matchURL);
            
                        const timelineURL = `https://europe.api.riotgames.com/lol/match/v5/matches/${matchId}/timeline`;
                        const timeline = await getData(timelineURL);
                        
                        if (Object.keys(matchInfo).length !== 0) {
                            const allowedTypeIds = [400, 420, 440];
                            const typeId = matchInfo.info.queueId;
                            const timelineInfo = collectTimelineInfo(timeline);
                            
                            pushMatchInDB(matchInfo, timelineInfo);
        
                            if (allowedTypeIds.includes(typeId)) {
                                const result = await pushInfoInDB(matchInfo.info);
                                
                                if (result === 'hey') {
                                    resolve(matchId);
                                }
                            }
                        }
                    }
                })
            }
        })
    }

    answers.push(func());

    const res = await Promise.all(answers).then((answers) => {
        console.log(answers);
        return 'hey';
    })

    if (res === 'hey') {
        console.log(3, res);
        return res;
    }
}

А так модуль pushInfoInDB. Именно в этом модуле происходит непосредственное добавление данных БД.

module.exports = async (obj) => {
    const answers = [];

    const func = () => {
        return new Promise((resolve, reject) => {
            for (let key in obj) {
                const {sumId, sumName, win, solo, flex, normal} = obj[key];
                const {champName, champId, kills, deaths, assists, physical, magic, trueDmg, restore, shield, cs, gold, vision, wards} = obj[key].champion;
                const {date, matchType, dmgTaken, CC, killingSpree, double, triple, quadra, penta} = obj[key].champion;
                const role = (obj[key].role).toLowerCase();
                
                const dmg = physical + magic + trueDmg;
                const heal = restore + shield;
                const kda = calcRatio((kills + assists), deaths);
                const records = {kda, kills, deaths, assists, dmg, heal, cs, gold, vision, wards, dmgTaken, CC, killingSpree, double, triple, quadra, penta};
        
                let type = '';
                if (solo) type = 'solo';
                if (flex) type = 'flex';
                if (normal) type = 'normal';
                
                summoner.updateOne({sumId: sumId}, {...}, {upsert: true}, (error, writeOpResult) => answers.push(resolve(sumId)));
        
                for (let key in records) {
                    const value = records[key];
        
                    summoner.updateOne({sumId: sumId, [`records.${key}.value`]: {$lt: value}}, {...});
                }
            }

            resolve(1);
        })
    }
    answers.push(func());

    const res = await Promise.all(answers).then((answers) => {
        console.log(answers);
        return 'hey';
    })

    if (res === 'hey') {
        console.log(1, res);
        return res;
    }
}

Помогите, пожалуйста, разобраться с проблемой. Моя благодарность будет безгранична!

Модуль collectTimeLineInfo

module.exports = (obj) => {
    if (!obj) return null;

    const frames = obj.info.frames;
    let participant = {};

    for (let i = 1; i <= 10; i++) {
        const lvlUp = [], itemPurchase = [];

        for (let frame of frames) {
            for (let event of frame.events) {
                if (event.participantId === i && event.type === "SKILL_LEVEL_UP") {
                    lvlUp.push({skill: event.skillSlot, time: event.timestamp});
                }

                if (event.participantId === i && event.type === "ITEM_PURCHASED") {
                    itemPurchase.push({item: event.itemId, time: event.timestamp});
                }

                participant[i] = {lvlUp, itemPurchase};
            }
        }
    }

    return participant;
}

Ответы (1 шт):

Автор решения: nörbörnën

Вообще, я сомневаюсь, что учёл всё (функции getData и pushMatchInDB так и остались за кадром, а в них наверняка много весёлого). Да и проверить попросту не на чем... Короче, попробуйте:

bruteForceMatches

module.exports = async (matchList) => {
  const answers = [];
  for (const matchId of matchList) {
    const doc = await match.findOne({ matchId });
    if (doc) {
      continue;
    }
    try {
      const matchURL = `https://europe.api.riotgames.com/lol/match/v5/matches/${matchId}`;
      const matchInfo = await getData(matchURL);
      if (Object.keys(matchInfo).length === 0) {
        continue;
      }

      const timelineURL = `https://europe.api.riotgames.com/lol/match/v5/matches/${matchId}/timeline`;
      const timeline = await getData(timelineURL);

      const allowedTypeIds = [400, 420, 440];
      const typeId = matchInfo.info.queueId;
      const timelineInfo = collectTimelineInfo(timeline);

      await pushMatchInDB(matchInfo, timelineInfo);

      if (allowedTypeIds.includes(typeId) && matchInfo.info) {
        await pushInfoInDB(matchInfo.info);
        answers.push(matchId);
      }
    } catch (err) {
      console.error(err);
    }
  }

  return answers;
};

pushInfoInDB

module.exports = async (obj) => {
  const answers = [];
  for (const key in obj) {
    try {
      const { sumId, sumName, win, solo, flex, normal } = obj[key];
      const { champName, champId, kills, deaths, assists, physical, magic, trueDmg, restore, shield, cs, gold, vision, wards } = obj[key].champion;
      const { date, matchType, dmgTaken, CC, killingSpree, double, triple, quadra, penta } = obj[key].champion;
      const role = (obj[key].role)?.toLowerCase();

      const dmg = physical + magic + trueDmg;
      const heal = restore + shield;
      const kda = calcRatio((kills + assists), deaths);
      const records = { kda, kills, deaths, assists, dmg, heal, cs, gold, vision, wards, dmgTaken, CC, killingSpree, double, triple, quadra, penta };

      let type = '';
      if (solo) type = 'solo';
      if (flex) type = 'flex';
      if (normal) type = 'normal';

      await summoner.updateOne(
        { sumId },
        { /**/ },
        { upsert: true }
      );
      answers.push(sumId);

      for (let key in records) {
        const value = records[key];
        await summoner.updateOne(
          { sumId: sumId, [`records.${key}.value`]: { $lt: value } },
          { /**/ }
        );
      }
    } catch (err) {
      console.error(err);
    }
  }
  return answers;
};
→ Ссылка