0

I am working on a flatMap with Promise.all; there are two condition inside flatMap, the originalObj is for checking whether originalObj.state is false or not, then implement the insertRealStartTime, and in every event, I will implement the Event.updateMany regardless the condition, and I want to return it as well because the return of Events.updateMany() told me whether or not the update is a success.

function async foo(){
  const eventPromises = events.flatMap(async (event) => {
      if (event.state.matchPhase == "1H") {
        // simpleQuery is async function
        const originalObj = await simpleQuery({ id: event.id });
        if (originalObj.state == false) {
          // insertRealStartTime is async function
          await insertRealStartTime(event.id);
        }
      }
      // Event.updateMany is async function
      await Events.updateMany(
        { ...event, expireAt: event["startTime"] },
      );
    }
  );
  const all = await Promise.all(eventPromises);
  console.log(all)
}

I got an array of undefined in console.log(all); I think I probably shouldn't use await inside flatMap because it lost the meaning of using Promise.all; however, how should I deal with all these if-statement to make sure the async function will execute base on the if-statement with Promise.all?

TungTung
  • 163
  • 7
  • You need to `return` from the flatMap callback, although `async` functions within a `flatMap` callback doesn't really work (see [here](https://stackoverflow.com/questions/53422511/wrap-background-color-around-text-aligned-right)). Seems like you might just want `.map()`. – Nick Parsons Aug 11 '23 at 04:11
  • Sorry, I can't see `flatMap` from the link, can you post an answer on how I can correct it to `.map()`? @NickParsons – TungTung Aug 11 '23 at 05:31
  • Sorry, I thought I edited my previous comment to correct the link, [this](https://stackoverflow.com/q/74959270/5648954) is the link I was supposed to send. But to me, it looks like you want to do `return insertRealStartTime(event.id);` and `return Events.updateMany(...)` (instead of `await`), and change `.flatMap()` to be `.map()` – Nick Parsons Aug 11 '23 at 05:33
  • [^](https://stackoverflow.com/questions/76880635/what-is-the-proper-way-to-write-conditional-statement-inside-flatmap-with-promis#comment135533880_76880635) @TungTung Instead of `.flatMap(async ...)`, you can use `.flat().map(async ...)` – jsejcksn Aug 11 '23 at 05:38
  • If I had two return inside `.map()`, will it be only returning only `insertRealStartTime(event.id)` but missed `Events.updateMany(...)` when fulfilling all condition? @NickParsons – TungTung Aug 11 '23 at 05:45
  • Except for the change to `.flat().map()` do I need to change any things? Do you mind adding an answer to show the corrected code? @jsejcksn – TungTung Aug 11 '23 at 05:49
  • @TungTung That's all you need to fix the `flatMap` problem, but it won't address your "array of undefined" problem — you never `return` anything from the callback function: did you intend to (and, if so, what)? – jsejcksn Aug 11 '23 at 05:52
  • The problem is if I try to change all `await` to `return`, it will only return the first async function, so may I ask what can I `return` things and can execute all fulfilled condition function in `.map`? @jsejcksn – TungTung Aug 11 '23 at 05:58
  • [^](https://stackoverflow.com/questions/76880635/what-is-the-proper-way-to-write-conditional-statement-inside-flatmap-with-promis?noredirect=1#comment135534083_76880635) @TungTung Don't _remove_ the `await` keywords and _replace_ them with `return`. Just `return` the value that you want to at the end of the function. If you don't need to return a value, then the array will always be full of `undefined`. Only you can tell us if you want to `return` something: do you? If so, what value do you want to return each time the callback is invoked? – jsejcksn Aug 11 '23 at 06:02
  • 1
    I want to return `await Events.updateMany()`, so should I just change the `await` to `return` in `await Events.updateMany()`? @jsejcksn – TungTung Aug 11 '23 at 06:12
  • It is not really clear what you want those promises to resolve to. I imagine that if `event.state.matchPhase` is "1H", you would want `originalObj` to be in your final array (is that what you expect?), but what if `event.state.matchPhase` is something else, then what do you expect to get in your final array? Do `insertRealStartTime` or `updateMany` resolve to some value that you need? If so, you currently ignore those values. Lots of clarification is needed about your expected array. – trincot Aug 11 '23 at 07:02
  • I have added the clarification to the question, thank you. @trincot – TungTung Aug 11 '23 at 08:26
  • What is the type of `events`? What is the desired type of `all`? – Bergi Aug 11 '23 at 11:12

1 Answers1

1

Your flatMap callback does not have a return statement, so the promises returned by those async calls will resolve to undefined.

As you want the get the values that the updateMany() promises resolve to, you should return those.

There are at least two ways to do that:

  1. Get the value that await Events.updateMany() evaluates to, and then return it (You would of course add the argument):

    const success = await Events.updateMany();
    return success;
    
  2. Return the promise returned by Events.updateMany():

    return Events.updateMany();
    

Either works.

Not a problem, but if the callback returns a promise (as is your case), there is no reason to use flatMap. flatMap would be useful if you expect arrays as return values for the callback, but that is impossible with async callbacks -- they always return promise objects. So you can just use map.

With some other updates to your code, you get this:

function async foo() {
  const eventPromises = events.map(async (event) => {
      if (event.state.matchPhase == "1H") {
        // You can use destructuring here, as you're only interested in the state property
        const {state} = await simpleQuery({ id: event.id });
        if (!state) { // Use NOT operator
          await insertRealStartTime(event.id);
        }
      }
      // Return the promise
      return Events.updateMany(
        { ...event, expireAt: event.startTime }
      );
    }
  );
  const all = await Promise.all(eventPromises);
  console.log(all);
  return all; // Provide the caller something to work with...
}
trincot
  • 317,000
  • 35
  • 244
  • 286