1

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?

0

1 Answer 1

1

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}])
  })
}
Sign up to request clarification or add additional context in comments.

Comments

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.