Jamie Hutber
Jamie Hutber

Reputation: 28116

Promise.all() returning all results as undefined

I am building up an array of promises from Mongoose's Model.save() But for some reason the returned data from Promise.all() is an array of undefined

Code

const saveDataArray = [];
//go through results and save them to the db
Object.keys(passData.scrapeUniqueData).map((index) => {
    const result = gamesExport.addGame(passData.scrapeUniqueData[index], passData.leagueInfo.league_id, passData.leagueInfo.leagueID, passData.leagueInfo.year);
    if(result)
    saveDataArray.push(result);
});

//const -> saveDataArray 
[Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise,  Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise, Promise]

return Promise.all(saveDataArray)
.then((savedDBData) => {
    console.info('savedDBData', savedDBData);
    console.info('saveDataArray', saveDataArray);
    passData.savedDBGames = savedDBData.filter(function(n){ return n != undefined });
    return passData;
})

//const -> savedDBData 
[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]

So imo savedDBData should be returning the same as `saveDataArray. Why isn't Promise.all returning the data that was saved?

AddGame

addGame: (details, league_id, leagueID, year) => {
    "use strict";
    if(!details.result && details.result[0] === "P"){
        console.error('result skipped for postponded match');
        return;
    }
    if (details && details.notes !== "Postponed" && !details.postponed) {
        var result = new Games();
        result.fixtureID = details.fixtureID;

        if (details.date.toString().indexOf('z') === -1) {
            result.date = Date.parse(moment(details.date.toString(), "DD-MM-YYYY H:m").format());
        } else {
            result.date = details.date;
        }
        result.home_id = details.home_id._id;
        result.away_id = details.away_id._id;
        result.league_id = league_id;
        result.leagueID = leagueID;
        result.year = year;
        result.norsemen = details.home_id.name.isNorsemen() || details.away_id.name.isNorsemen();

        if (details.result) {
            if (details.result.home === "A" && details.result.away === "A") {
                result.result = ['A', 'A'];
                result.postponed = true;
            } else if (details.result.home === "H" && details.result.away === "W") {
                result.result = ['H', 'W'];
            } else if (details.result.home === "A" && details.result.away === "W") {
                result.result = ['A', 'W'];
            } else if (details.result.home === "C" && details.result.away === "C") {
                result.result = ['C', 'C'];
                result.cancelled = true;
            } else if (details.result.home === "P" && details.result.away === "P") {
                result.result = ['P', 'P'];
                result.postponed = true;
            } else {
                result.result = [parseInt(details.result.home), parseInt(details.result.away, 10)];
            }
        }
        return result.save(function (err, saveData) {
            if (err) console.error(err);
            return result;
        });
    } else {
        return null;
    }
},

Upvotes: 0

Views: 485

Answers (1)

robertklep
robertklep

Reputation: 203554

When you pass a callback function to a Mongoose method, it assumes that you won't be using the promise that it returns as well.

I'm not sure if this is by design (I guess it is, because otherwise both the regular callback and the promise handler will be called, with the same result), but I can reproduce your issue with code that looks like this:

let doc = new Model(...);
doc.save((err, res) => {
  console.log('CB RES', res);
}).then(res => {
  console.log('PR RES', res);
});

PR RES ("promise result") is logged with a result of undefined, but CB RES ("callback result") logs a proper document. When you don't pass a callback function to save(), then PR RES logs the proper document.

So you should rewrite addGame to just return a promise, and not pass in a callback function:

return result.save().catch(function(err) {
  console.error(err);
  // XXX: be aware that if you don't do anything else here,
  //      the error will _just_ be logged, but not propagated.
  //      This is also what your original code does, so I assume
  //      it's intentional.
});

Upvotes: 1

Related Questions