Home > Software engineering >  ForEach not looping. Typscript, Firebase Functions
ForEach not looping. Typscript, Firebase Functions

Time:11-15

There are a lot of similar questions here on this topic, but all seem to have very specific answers that don't seem to apply to my case.

I have a Google Firebase RTB datasnapshot getting passed to this function. I want to turn that snapshot into an array of custom objects. each object represent a child node and all sub children. I would also like to do some processing on the child data before returning the array. The post processing is the issue, as you cant call await on a function within a foreach.

After digging, I found this approach on StackOverflow, creating a sub function for parsing the data and storing all the promises in their own array, and calling (awaiting) the getData() function from the top level:

export async function unpack_snap(snap: any): Promise<(CustomObject[] | null)>{
    const toWait: any[] = [];
    console.log(JSON.stringify(snap)); 

    await snap.forEach(async obj => {  
        toWait.push(obj_from_snap((obj)));    // add this promise to the array
        console.log(obj.key);           // I added this to see if it was looping 
    });

    await Promise.all(toWait);
    return toWait;
}

export async function obj_from_snap(co: DataSnapshot) : Promise<(CustomObject | null)>{

        var newCO: CustomObject = {
            val1 : co.val().val1,
            val2 : co.val().val2,
            Data : await GetData(co.key)
        };
        console.log(`Data: ${newCO.Data}`)
        return newCO;
}

export async function getData(key: String) Promise<(String | null)>{
...
}

Unfortunately, this returns an array with an empty object (Logs show this: [{}] ). The logging output in the forEach only ever triggers once, even if the Stringified JSON of the snap shows more than one valid child. Same with the logging of newCO.Data in the helper function.

Why is this process not looping?

Also, if I return the toWait[] array, will it contain all of the CustomObject objects that were outputs of my helper function? If not, is there a better approach that yeilds me an array of CustomObject, each from a different function call? Modified JSON as an output would also work.

Any suggestions? Thank you for your time.

UPDATE

I attempted to just loop through the ForEach and print the key.

    await snap.forEach(async obj => {  
        console.log(obj.key);           // I added this to see if it was looping 
    });
    return null;

As before, the first child key gets printed and the function exits, returning null, regardless of how many child nodes there are. I don't understand why the code is not iterating through the loop, and this leads me to believe that its not an issue of Promise.all(). Thoughts?

CodePudding user response:

I was able to answer both of my questions! Posting here in case someone finds this one day...

export async function unpack_snap(snap: any): Promise<(any[] | null)>{
    var array: any[] = [];          // Array of objects
    const toWait: any[] = [];       // Array of promises
    console.log(JSON.stringify(snap));   // Log the input for debugging

    await snap.forEach(function(obj) {     // CHANGED FROM async (obj) to function (obj)
        toWait.push(obj_from_snap((obj)).then((result) => array.push(result)));    // Added a chained promise to the first, which adds the result to my output array
    });
    await Promise.all(toWait);   // wait until all promises are complete
    return array;                // return the array
}

This is working as expected.

  • Related