I have a firestore collection structure like this
Chat Collection
"chats": {
"xyz_doc_id_1": { msg: "one", sender_id: "xyz123", timestamp: "xyz" }, //Chat from Person A
"xyz_doc_id_2": { msg: "two", sender_id: "xyz456", timestamp: "xyz" }, //Chat from Person B
"xyz_doc_id_3": { msg: "three", sender_id: "xyz123", timestamp: "xyz" }, //Chat from Person A
"xyz_doc_id_4": { msg: "four", sender_id: "xyz456", timestamp: "xyz" }, //Chat from Person B
}
User Collection
"users": {
"xyz_user_1": { uid: "xyz123", name: "Person A" },
"xyz_user_2": { uid: "xyz456", name: "Person B" },
}
Now I have to store chats data like
const chatData = [
{msg: "one", sender_name: "Person A"},
{msg: "two", sender_name: "Person B"},
{msg: "three", sender_name: "Person A"},
{msg: "four", sender_name: "Person B"},
]
But for this, I have to first fetch the data of the chat, from which I will get the user's ID for each document. Now then, based on every user's ID I have to fetch the user names.
For which I am using this kind of nested code.
const asynFunction = async () => {
const chatList = await db.collection("chat").orderBy("timestamp").get()
chatList.forEach((chatDoc) => {
const msg = chatDoc.data().msg // Chat Message
const sender_id = chatData.data().sender_id // Sender ID
//Till here I am getting data in sequence
//Here I want each sender's name on the basis of SENDER ID
db.collection("users").doc(sender_id).get().then((docForName) => {
const senderName = docForName.data().name
//Here I am storing msg and name
setChatData((prev) => [...prev, {msg: msg, name:senderName}])
})
})
}
Expected Output -
msg: "one", name: "Person A", //From Person A
msg: "two", name: "Person B", //From Person B
msg: "three", name: "Person A", //From Person A
msg: "four", name: "Person B", //From Person B
And what I am getting -
msg: "one", name: "Person A", //From Person A
msg: "three", name: "Person A", //From Person A
msg: "two", name: "Person B", //From Person B
msg: "four", name: "Person B", //From Person B
I've done that with chained conditional as well but result is same. How can this be done in sequence order?
CodePudding user response:
One way to do this is to use for of
instead of forEach
, so that the get
calls get executed one by one:
const asynFunction = async () => {
const chatList = await db.collection("chat").orderBy("timestamp").get()
for (const chatDoc of chatList.docs) {
const msg = chatDoc.data().msg // Chat Message
const sender_id = chatData.data().sender_id // Sender ID
const docForName = await db.collection("users").doc(sender_id).get();
const senderName = docForName.data().name
//Here I am storing msg and name
setChatData((prev) => [...prev, {msg: msg, name:senderName}])
})
}
Also see: Using async/await with a forEach loop
Another way would be to use Promise.all
to wait for all promises to finish, and then process them in the same order:
const asynFunction = async () => {
const chatList = await db.collection("chat").orderBy("timestamp").get()
const promises = chatList.docs.map((chatDoc) => {
const msg = chatDoc.data().msg // Chat Message
const sender_id = chatData.data().sender_id // Sender ID
return db.collection("users").doc(sender_id).get();
});
const results = Promise.all(promises);
results.forEach((docForName) => {
const senderName = docForName.data().name
setChatData((prev) => [...prev, {msg: msg, name:senderName}])
})
}