Navigating through nested Firebase realtime DB queries using await/async techniques

In the process of developing a Firebase function (Gist), I encountered a challenge that I'm seeking assistance for.

  1. The function starts by querying a realtime database reference (events) using this code:

     await admin.database().ref('/events_geo').once('value').then(snapshots => {

  2. It then proceeds to iterate through all the events with this snippet:

     snapshots.forEach(snapshot => {

  3. Next, it filters events based on a specific criterion for further processing.

  4. Subsequently, multiple queries are made to the realtime database to retrieve details related to each event like so:

     await database().ref("/ratings").orderByChild('fk_event').equalTo(snapshot.key).once('value').then(snapshots => {

  5. Data is prepared for SendGrid and the processing is finalized.

Although the data processing functions correctly, I am facing an issue where the outer 'await' command mentioned in point 1 does not wait for the inner awaits (the queries to the realtime DB) to complete. Consequently, when it's time to call SendGrid, the data is empty initially, only arriving a moment later. Reviewing the Firebase function logs below can provide more clarity:

 10:54:12.642 AM Function execution started

 10:54:13.945 AM There are no emails to be sent in afterEventHostMailGoodRating

 10:54:14.048 AM There are no emails to be sent in afterEventHostMailBadRating

 10:54:14.052 AM Function execution took 1412 ms, finished with status: 'ok'

 10:54:14.148 AM <p style="margin: 1em 0px;">Super hyggelig aften :)</p><p style="margin: 1em 0px;">super oplevelse, ... long string generated

Gist displaying the concerned function

I suspect my confusion lies within the asynchronous nature of my async/await statements, particularly due to nested awaits. Although breaking down the code into smaller units might help, it could lead to complex integration of numerous awaits, making it less readable.

Therefore, I have two questions at hand. Is there a solution for this issue in the existing code structure? Additionally, what would be the most effective approach to handle such scenarios involving additional processing post retrieval from the Realtime DB?

Regards, Simon

Answer №1

One potential issue you may encounter is the utilization of async within a forEach loop in this section:

  Object.keys(event.participants).forEach(async (value: any) => {

It's crucial to note that forEach loops do not support asynchronous functions. To address this, consider mapping the data to a regular array and implementing a for loop instead. This way, you can utilize await appropriately.

Answer №2

After receiving valuable guidance from Tarik Huber's response, I decided to refactor the function and simplify it significantly.

The key points that helped me were:

  1. Avoid using forEach and instead opt for iterating with for(const event of events), which is better suited for asynchronous calls.
  2. Divide the function into smaller, modular parts. One part now handles fetching, filtering, and storing data in an array, while the second part iterates through the array and makes additional async calls.

This approach resulted in code that was easier to read and debug. The original function attempted to perform both tasks simultaneously using forEach, leading to issues with unresolved async calls.

An overview of the updated function is provided below, highlighting only the crucial sections.

async function afterEventHostMail() {
 // Initialize variables
  events = [];

  await admin.database().ref('/events_geo').once('value').then(snapshots => {
    snapshots.forEach(snapshot => {
      var event = snapshot.val();
      var eventKey = snapshot.key;
      
      // Implement some filtering
      const mergedObj = { ...event, ...{ key: eventKey } };
      events.push(mergedObj)
    });
  });

  for (const event of events) {
    // Perform numerous await calls here
  }

  // Proceed with the remaining functionality within the function
}

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

What steps can be taken to resolve the Angular error stating that the property 'bankCode' is not found on type 'User' while attempting to bind it to ng model?

I'm encountering an issue with my application involving fetching values from MongoDB and displaying them in an Angular table. I've created a user class with properties like name and password, but I keep getting errors saying that the property doe ...

Ways to display all utilized typescript types within a project

Here is a snippet of code I'm working with in my project: describe('Feature active', () => { it('Should render a Feature', () => { const wrapper = shallow(<MyComponent prop1={1}/>); expect(wrapper.prop('p ...

Links in Next.js fail to function properly after deploying on Firebase

I recently deployed my project on Firebase, but I'm encountering an issue with the links not functioning correctly. Everything works fine when tested locally, with paths like /account working as expected. However, after deployment, only /account.html ...

Is there a way to bypass the "Error: Another application is currently displaying over Chrome" message using Javascript or Typescript?

Can the "Another app is displaying over chrome error" be bypassed using JavaScript or TypeScript? Error Message: https://i.stack.imgur.com/iSEuk.png ...

What is the reason for the removal of HTML tags in the environment when converting Angular dependencies from es2015 to esm2015 during

After completing the generation of the browser application bundle in Intellij, I noticed that the HTML tags cannot be resolved anymore. What could be causing this issue? I also discovered that if I don't include the AngularMaterialModule in the AppMo ...

Converting retrieved data into table cells through mapping

I'm facing an issue where I need to display specific addresses for each individual in a table row. For simplicity, let's focus on showing the city specifically as described in this code snippet: https://i.stack.imgur.com/bJmsD.png Currently, whe ...

How can I pass DOCUMENT in Angular?

In my directive, I use dependency injection to access the DOCUMENT and set up an event listener: constructor(@Inject(DOCUMENT) private document: Document) {} ngOnInit() { this.document.addEventListener('click', this.clicked, true); } @Bound ...

Can anyone guide me on troubleshooting the firebase import error in order to resolve it? The error message I am encountering is "Module not found: Error:

When attempting to import the 'auth' module from my 'firebase.js' file, I encountered an error. I used the code import {auth} from "./firebase", which resulted in the following error message: Error: Unable to locate module &a ...

Unable to retrieve real-time data from Firestore using getStaticPaths in Next.js

While fetching data from Firebase Firestore using getStaticProps is successful, I encounter a 404 page when attempting to implement the logic for retrieving details of individual items with getStaticPaths. The current state of my [id].js code appears as fo ...

Trouble arises in TypeScript when defining a class - SyntaxError crops up

When I try to declare a class, I encounter an error: // The code below is from my test1.ts file class WDesign { wModel: string; wQuer: string; } let logWDesign = (wd : WDesign) => { console.log(wd.wModel + " " + wd.wQuer); } let wd1 : WDe ...

How can eslint be used to enforce a particular named export?

Is there a way to use eslint to make it mandatory for JavaScript/TypeScript files to have a named export of a specific name? For instance, in the src/pages folder, I want all files to necessitate an export named config: Example of incorrect usage src/page ...

The feature of Nuxt 3's tsconfig path seems to be malfunctioning when accessed from the

Take a look at my file structure below -shared --foo.ts -web-ui (nuxt project) --pages --index.vue --index.ts --tsconfig.json This is the tsconfig for my nuxt setup. { // https://v3.nuxtjs.org/concepts/typescript "exte ...

My function doesn't seem to be cooperating with async/await

const initialState={ isLoggedIn: false, userData: null, } function App() { const [state, setState]= useState(initialState) useEffect(()=>{ async function fetchUserData(){ await initializeUserInfo({state, setState}) // encountering an ...

What is the resolution if I need to utilize a property that is untyped?

Transitioning to TypeScript from plain old JavaScript is a step I'm taking because I believe it offers significant advantages. However, one drawback that has come to light is that not all attributes are typed, as I recently discovered. For instance: ...

Learn how to effortlessly move a file into a drag-and-drop area on a web page with Playwright

I am currently working with a drag-zone input element to upload files, and I am seeking a way to replicate this action using Playwright and TypeScript. I have the requirement to upload a variety of file types including txt, json, png. https://i.stack.img ...

Utilizing constants within if statements in JavaScript/TypeScript

When working with PHP, it is common practice to declare variables inside if statement parenthesis like so: if ($myvar = myfunction()) { // perform actions using $myvar } Is there an equivalent approach in JavaScript or TypeScript?: if (const myvar = myf ...

getItemForm does not make a second promise call

I have a scenario where my function calls the api.send service twice, however when I run a test expecting it to resolve both promises, only res1 is returned and not res2. How can I ensure that both promises are resolved successfully? Here is my function: ...

How to retrieve the HTTPClient value in Angular?

APIservice.ts public fetchData(owner: any) { return this.http.get(`${this.url}/${owner}`, this.httpOptions).pipe( catchError(e => { throw new Error(e); }) ); } public fetchDataById(id: number, byId:string, owner: any) { ...

Enhancing data validation and converting strings to dates with Nest.js - DTO approach

Anticipating the upcoming request to adhere to the ISO 8601 standard timestamp format, something similar to "2023-12-04T15:30:00Z" (typically embedded as a string within JSON data that needs conversion to a JavaScript Date object). This is my Data Transfe ...

Can you explain the distinction between Reflect.getMetadata and Reflect.getOwnMetadata?

Just like the title says, the reflect-metadata API comes with a method called getMetadata and another called getOwnMetadata. Can you explain the distinction between them? The same question applies to hasOwnMetadata, and so on. ...