Tips on retrieving data in sequential order from a nested forEach function or loop

My structure in firestore collection looks 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" },
      }

I am now tasked with storing the chat data as follows

    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"},
    ]

To achieve this, I need to first retrieve the chat data to extract the user IDs for each document. Then, using these IDs, I have to fetch the corresponding user names.

This involves utilizing nested code like below

    const asyncFunction = 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

        //At this stage, the data is retrieved sequentially

        //I now require each sender's name based on their SENDER ID
        db.collection("users").doc(sender_id).get().then((docForName) => {
          const senderName = docForName.data().name

          //Here I store the message and name
          setChatData((prev) => [...prev, {msg: msg, name:senderName}])
        })
      })
    }

The Expected Output is -

   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

However, what I actually receive is -

   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 have tried chaining conditions as well but the outcome remains unchanged. How can I ensure sequential order?

Answer №1

To implement this functionality differently, consider utilizing for of instead of forEach. This way, the get calls will be executed sequentially:

const asyncFunction = 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;

    // Storing message and name
    setChatData((prev) => [...prev, {msg: msg, name: senderName}]);
  }
}

For more details, visit: Using async/await with a forEach loop


Another approach is to utilize Promise.all to wait for all promises to complete before processing them in order:

const asyncFunction = 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}]);
  });
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Achieving the extraction of a particular string from an HTML element using JavaScript

<input id="WD01B3" ct="CB" lsdata="{2:'WD01B4',4:'Any',20:'\x7b\x22WDA_TYPE\x22\x3a\x22DROPDOWN_BY_KEY\x22,\x22WDA_ID\x22\x3a\x22ABCA950297D2C0C432BAB9BB ...

Clicking to reveal a v-date-picker v-menu and automatically focusing on a v-text-field within it?

I implemented a date-picker component in my app following the instructions from Vuetify. To enhance usability for desktop users, I removed the readonly attribute to allow manual input. Now, desktop users can easily navigate through form fields using th ...

The error message "Unable to display 'show' property of undefined using $mdToast" is displayed

I can't seem to figure out what's causing this issue... Following the Angular material design guidelines, I expected this code to work. However, I keep getting an error that says: TypeError: Cannot read property 'show' of undefined H ...

Initiate the command with given parameters

Currently, I am utilizing a combination of React, Redux, Rxjs, typesafe-actions, and TypeScript to invoke an action with parameters. Here is my current code: Actions: import { createAsyncAction } from 'typesafe-actions'; import {ICats} from &ap ...

Ways to verify if a variable holds a JSON object or a string

Is it possible to determine whether the data in a variable is a string or a JSON object? var json_string = '{ "key": 1, "key2": "2" }'; var json_string = { "key": 1, "key2": "2" }; var json_string = "{ 'key': 1, 'key2', 2 } ...

Exploring the possibilities of integrating Keycloak with the powerful nuxt-auth

I am incorporating this particular authentication module in conjunction with Keycloak. In my nuxt.config.js configuration: keycloak: { _scheme: 'oauth2', client_id: 'client-bo', userinfo_endpoint: 'SERVER/protocol/open ...

Incorporating images into CSS using an npm package

My npm package has the following structure: --src --styles -image.png -style.scss In the style.scss file, the image is referenced like this: .test { background-image: url(./image.png); } The issue arises when consuming the package, as th ...

jsTree eliminates the hashtag from the URL

Utilizing a JSON generated jsTree to efficiently navigate through a directory structure has been my recent task. I have successfully implemented the select_node event to capture the path of the selected node as a string and then update the location.hash ...

Exploring the capabilities of React useRef and querying multiple elements with query

I'm currently using react with useRef for my project. In the past, I used to query the rows of a table like this: const rows = document.querySelectorAll('table tr'); However, I now have multiple tables on the same page and need to utilize ...

The React ternary operator within HTML does not display the correct HTML output

I'm currently learning React and facing a challenge with using a ternary operator. My goal is to display a minus sign by default, and then switch it to a plus sign when clicked. I implemented the ternary operator in my JSX and set the initial state of ...

Enable/Disable Text Editing Based on Vue Js Input

I’m working on a way to make certain parts of a string in an input editable or non-editable (readonly) depending on the context in Vue.js. For instance: I have this text: My Name is $John Doe$ Now, I want my Vue.js code to scan the string and allow edi ...

Utilizing Node.js with Express and the less-middleware in combination with Bootstrap 3

I have recently delved into learning Node.js and I am currently in the process of setting up an express installation with less-middleware while also incorporating Bootstrap 3 less files. However, my search for tutorials has only yielded results related to ...

Error: Unable to locate module pathway in eslint/typescript configuration

My .eslintrc.json configuration is: { "env": { "browser": true, "commonjs": true, "es6": true, "node": true, "jest": true }, "parserOptions ...

Iterate through an array of objects and add them to a fresh array

I am encountering an issue where I would like to generate a fresh array of objects in order to avoid utilizing a nested array map. However, the error message below is being displayed: TypeError: Cannot read property 'subscriber_data' of undefine ...

Error encountered in CasperJS due to modifications made using WinSCP

I am facing an issue with a casperjs script: var casper = require('casper').create(); console.log("casper create OK"); casper.start("https://my-ip/login_page.html", function() { console.log("Connection URL OK"); // set a waiting condi ...

Exploring new ways to navigate between pages in ReactJS using the Bootstrap Nav component

I'm a beginner in the world of reactjs and I'm trying to connect my pages using a NavBar function that I have created. When I click on the 'Companies' button, the URL changes correctly to 'http://localhost:3000/companies.js' b ...

Process executes another process

Can anyone assist me with a JavaScript inquiry? I am curious if it is feasible to implement this: variable: { info1: 'info1', info2: 'info2', show: false, someNameFunction: functionWhichIWantRun(row) } So, after defining the var ...

Send an HTML form using Django and Ajax for submission

I am excited to submit a form using Ajax for the first time. Here is the code I have: index.html (where the form is located): form method="post" role="form" class="email-form" id="contact_me"> ...

The functionality of Materialize CSS tabs appears to be malfunctioning

I've been working on a mobile profile UI and using materialize css, but unfortunately the tabs aren't functioning properly. Here's the code snippet: http://codepen.io/anon/pen/VmmJWv html: <meta name="viewport" content="width=device-w ...

Issue with Jquery UI dialog not responding to `Escape` key press for closing the dialog

Whenever a user triggers a dialog, multiple ajax requests are initiated and processed. To streamline this process, I have implemented a secondary dialog that showcases loading information until all the requests are completed. An issue I am facing is the i ...