1

In my current project, using Firebase as backend, I have a dedicated function to remove inactive users upon certain criteria (not relevant for this question).

Within my Firebase function, I have this internal function that is used to fetch the inactive users, but it always returns an empty array:

async function getInactiveUsers(users: any[], nextPageToken?: any): Promise<any> {
    const getUsers: any = await admin.auth().listUsers(1000, nextPageToken);
    const threeMonthsAgo = new Date(Date.now())
    threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3)   
    const inactiveThreeMonthsUsers: any = getUsers.users.filter((user: any) => 
        Date.parse(user.metadata.lastSignInTime) < threeMonthsAgo.getTime()
    );  
    if(inactiveThreeMonthsUsers.length > 0){
        inactiveThreeMonthsUsers.forEach(async (user: any) => {
            const UserDataRef = admin.firestore().collection('Collection').doc(user.uid);
            const UserDataGet = await UserDataRef.get();
            const UserData: any = UserDataGet.data();
            if((UserData.firstCriteria < 1) && (UserData.secondCriteria === 0)){
                users.push(user.uid);
            }
        });       
        if (getUsers.pageToken) {
            return getInactiveUsers(users, getUsers.pageToken);
        }      
        return users;
    } else {
        return 0
    }
}

I have loged the users array right after the push method method, like that :

if((UserData.firstCriteria < 1) && (UserData.secondCriteria === 0)){
    users.push(user.uid);
    console.log("users: " + users)
}

And that console.log displays the contents with the data inside the array, but the function still returns an empty array.

I added a value in the array before the forEach:

async function getInactiveUsers(users: any[], nextPageToken?: any): Promise<any> {
    users.push("test");
    // ...the rest of the code
}

And this item is returned. So that made me think that the forEach loop appends a copy of the array.

I also tried to store the user argument in a new array, declared at the top of this function, then append it with the push() method. But also that doesn't work.

What is wrong with my approach?

2
  • Sorry maybe it's a lack of understand on my side, but I thought my getUsers awaits the list of users. I mean I have const getUsers: any = await admin.auth().listUsers(1000, nextPageToken); For the rest generally my code editor tells me if there is a bad Promise handling. It's no present in my question but when I call this function I awaits it. My code is inspired from what is provided by Firebase on their Github github.com/firebase/functions-samples/blob/master/… Commented Mar 9, 2021 at 21:19
  • No you are right, there is no problem there. I misread the code. The problem is in the forEach which makes all iterations without waiting. The await in the callback only makes the callback wait, but not forEach. Commented Mar 9, 2021 at 21:51

1 Answer 1

4

A forEach loop will run synchronously, while the async callback you pass to it will partly run asynchronously (the part after await).

To make the loop iterations wait on the asynchronous code before going to the next iteration, use a for loop.

for (let user of inactiveThreeMonthsUsers) { .... await .... }
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, indeed replacing my forEach by a for like you showed did the trick.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.