Nawaz Mohamed
Nawaz Mohamed

Reputation: 155

How can we return data's from firebase queries with async await

Hi I have an array of document id's of a users collection. I want to retrieve a user data array with all user's data' some parameters in an object for every document of the users collection for given id's from the array of documents id's.

But with my current code the returned value is returned before the promise is solved, thus it is an empty array.

Can somebody explain me more on how to implement this asynchronous call, and what is the problem with this.

This is my code

export const getChatInfo = async chatIdsArray => {
  const userData = new Array();
  await chatIdsArray.forEach(async chatId => {
    const documentSnapshot = await firestore()
      .collection('users')
      .doc(chatId)
      .get();

    if (documentSnapshot.exists) {
      const {fname, lname, userImg} = documentSnapshot.data();
      userData.push({
        fname: fname,
        lname: lname,
        userImg: userImg,
      });
    }
    console.log(`userdata in getchatinfo inner : ${JSON.stringify(userData)}`); // this returns correct array
  });
  console.log(`userdata in getchatinfo outer : ${JSON.stringify(userData)}`); // this return an empty array
  return {userData};
};

Upvotes: 0

Views: 287

Answers (1)

LeadDreamer
LeadDreamer

Reputation: 3499

You're anticipating some the the user documents to be empty, which is (I assume) why you don't want to use .map(). Unfortunately, .forEach() is not asynchronous, so it doesn't help you here. Enter one of my favorite patterns - the .reduce() loop of chained Promises:

export const getChatInfo = async chatIdsArray => {
   return chatIdsArray.reduce(async (resultArray, chatId) => {
    const documentSnapshot = await firestore()
      .collection('users')
      .doc(chatId)
      .get(); //documentSnopshot will be a PROMISE
    let outArray = await resultArray; //resultArray carries the reduce PROMISE
    if (documentSnapshot.exists) { //will wait for the above PROMISE
      const {fname, lname, userImg} = documentSnapshot.data();
      outArray = await outArray.concat({ // this will be a PROMISE
        fname: fname,
        lname: lname,
        userImg: userImg,
      });
    }
    return outArray; //either path, will be a PROMISE

    }, Promise.resolve([])); //this "empty" promise starts the chain
};

you could also write this as .then() chains

export const getChatInfo = (chatIdsArray) => {
  return chatIdsArray.reduce((resultArray, chatId) => {
    return resultArray
      .then((outArray) => {
        return firestore().collection("users").doc(chatId).get();
      })
      .then((documentSnapshot) => {
        if (documentSnapshot.exists) {
          const { fname, lname, userImg } = documentSnapshot.data();
          return Promise.resolve( //the Promise.resolve() keeps the promise chain going
            resultArray.concat({
              fname: fname,
              lname: lname,
              userImg: userImg
            })
          );
        }
        return Promise.resolve(resultArray); //will be a promise
      });
  }, Promise.resolve([]));
};

Upvotes: 1

Related Questions