Reputation: 155
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
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