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

How can I access a file uploaded using dxFileUploader?

I am facing an issue with retrieving a file from dxFileUploader (DevExpress) and not being able to read it in the code behind. The file is only appearing as an object. Here is My FileUploader : { location: "before", ...

Deleting data from Firebase in Angular can be easily done using the AngularFire library. By

I am attempting to remove specific values from my Firebase database. I need to delete this entry from Firebase: https://i.stack.imgur.com/CAUHX.png So far, I have tried using a button to trigger the delete function like this: <div class="single-bfunc ...

Using Angular 2, NodeJS, and Mongoose to send data from an Angular 2 frontend to a NodeJS backend REST API. However, encountering an issue where the Node API logs show that the OPTIONS

I am facing an issue with sending data from my Angular2 frontend API to the backend client, which is built using NodeJS and mongoose. When I inspect the data being sent on the Angular2 client through console.log, I can see that the correct values are being ...

I am unfamiliar with this scenario but I can utilize Axios, async/await, and TypeScript to navigate it

Having trouble creating a workflows list from an axios response Error: Argument of type 'Promise<unknown>' is not assignable to parameter of type 'SetStateAction<WorkflowForReactFlowProps[] | null>'. Here's the Axios c ...

Angular - Ensuring correct rendering of a subcomponent with input parameter on the first update

Here is a snippet of code showcasing a list of educations and a component: <cdk-virtual-scroll-viewport itemSize="5" class="list-scroll"> <app-education-item *ngFor="let education of loadedEducations" ...

Compiling TypeScript files with an incorrect path when importing, appending "index" at the end of the @angular/material library

I'm currently working on creating a library to collect and distribute a series of Angular components across various projects, with a dependency on angular/material2. My objective is to eventually publish it on npm. However, I've encountered an i ...

Encountering: error TS1128 - Expecting declaration or statement in a ReactJS and TypeScript application

My current code for the new component I created is causing this error to be thrown. Error: Failed to compile ./src/components/Hello.tsx (5,1): error TS1128: Declaration or statement expected. I've reviewed other solutions but haven't pinpointed ...

ESLint not functioning properly on TypeScript (.ts and .tsx) files within Visual Studio Code

After installing the ESLint extension in VSC, I encountered an issue where it was no longer working on the fly for my React project when I introduced Typescript. In the root of my project, I have a .eslintrc file with the following configuration: { "pa ...

Develop a directive for transforming data

In my latest project, I am looking to develop a LoaderDirective that can fetch an observable, display a spinner while loading the data, and then switch to showing the actual data once loaded. I also want it to expose the loaded data using the 'as&apos ...

Demonstrate JSON data using ngFor loop in Angular

Need some assistance here. Trying to display data from a .json file using a ngFor loop. However, I keep running into the following error in my code: Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgF ...

Angular v15 Footer Component Table

In my Angular 15 project, I am attempting to correctly position and utilize the mat table with the following code snippet: <tr mat-footer-row *matFooterRowDef="displayedColumns"></tr>. While the displayedColumns property is functionin ...

How to add an item to an array in JavaScript without specifying a key

Is there a way to push an object into a JavaScript array without adding extra keys like 0, 1, 2, etc.? Currently, when I push my object into the array, it automatically adds these numeric keys. Below is the code snippet that I have tried: let newArr = []; ...

How can I use the target type (and maybe even the property type) as a type parameter within a decorator?

In the process of incorporating a deep-watch property decorator in Angular, the following usage has been implemented: @Component({ /* ... */ }) export class AppComp { @Watch( 'a.b.c', function (last, current, firstChange) { // ca ...

Upon deployment, Angular encounters issues with routing to lazy loaded modules

I recently completed development on a new Angular application that utilizes lazy loading for improved performance. During local testing using ng serve (or ng serve --prod to mimic production mode), the app compiled without errors and functioned properly. ...

Arrow functions do not function properly with Typescript decorators

I've created a typescript decorator factory that logs the total time taken to execute a function, along with the actual function execution results and parameters passed to the decorator. For example: export function performanceLog(...args: any[]) { ...

Utilizing TypeScript with Svelte Components

I've been struggling to implement <svelte:component /> with Typescript without success. Here's my current attempt: Presentation.svelte <script lang="ts"> export let slides; </script> {#each slides as slide} & ...

Setting a value in Ionic 3 HTML template

Attempting to assign a value in an Ionic 3 template from the ts file while also adding css properties but encountered an issue. PROBLEM Error: Uncaught (in promise): Error: No value accessor for form control with name: 'image' Error: No va ...

React: Using useState and useEffect to dynamically gather a real-time collection of 10 items

When I type a keystroke, I want to retrieve 10 usernames. Currently, I only get a username back if it exactly matches a username in the jsonplaceholder list. For example, if I type "Karia", nothing shows up until I type "Karianne". What I'm looking f ...

Unable to utilize React Icons component as an object value in typescript

Currently, as I develop my personal website using typescript and react, I am faced with an issue in the footer section. I have an array of objects with url and icon properties that I map through to display different icons on each iteration. Initially, this ...

Error code 2532 occurs when trying to access an object using square brackets in TypeScript

Encountered the ts error: Object is possibly 'undefined'.(2532) issue while trying to access the value of a field within an object, where the object key corresponds to a value in an Enum. Below is a concise example to showcase this problem: en ...