Develop a JSON structure by retrieving nested documents using Firebase Firestore and Express

I'm currently working on developing an application using Express and Firebase Cloud Functions. I'm facing a challenge in creating a nested JSON structure based on the database schema specified below:

https://i.sstatic.net/2vI8z.png

Below is the code snippet that I am using:

exports.tstMenu = (req, res) => {
    let shop = db.collection('shops').doc(req.params.name).collection('menus');
    shop.get()
    .then((data) => {
        let menu = [];
        data.forEach((doc) => {
            let categories = getCategories(doc.id, shop);
            menu.push({
                menuID: doc.id,
                name: doc.data().name,
                position: doc.data().position,
                categories: categories,
            });
            console.log(menu);
        });
        return res.json(menu);
    })
    .catch((err) => {
        console.error(err);
        return res.status(500).json({ error: err.message});
    });
}

function getCategories(id, db){
    let shop = db.doc(id).collection('categories');
    return shop.get()
    .then((data) => {
        let categs = [];
        data.forEach((doc) => {
            var menuElements = [];//getMenuElement(doc.id, shop);
            categs.push({
                catID: doc.id,
                name: doc.data().name,
                position: doc.data().position,
                menuElements: menuElements,
            });
        });
        return categs;
    });
}

The output of tstMenu is as follows:

https://i.sstatic.net/z08yf.png

However, the log displays this:

https://i.sstatic.net/pZLjA.png

I'd appreciate any assistance in understanding how to address this issue. It seems like the promises are not being resolved when tstMenu reaches return res.json(menu);

Answer №1

The issue you are facing can be traced back to this particular line :

let categories = getCategories(doc.id, shop);

getCategories happens to be an asynchronous method. It returns a promise, therefore it cannot be used directly in this manner.

You have two options - either perform your assignment within a then callback or utilize async await.

exports.tstMenu = (req, res) => {
    let shop = db.collection('shops').doc(req.params.name).collection('menus');
    shop.get()
    .then((data) => {
     let menu = [];
     const promises = data.docs.map((doc) =>  // update from forEach to map
            getCategories(doc.id, shop).then(categories =>{
               menu.push({
                menuID: doc.id,
                name: doc.data().name,
                position: doc.data().position,
                categories: categories,
            });
        );

     return Promise.all(promises).then(()=> res.json(menu)); // responds once all promises are fulfilled
       
    })
    .catch((err) => {
        console.error(err);
        return res.status(500).json({ error: err.message});
    });
}

Alternatively,

exports.tstMenu = async (req, res) => {
  try {
    let shop = db.collection('shops').doc(req.params.name).collection('menus');
    const data = await shop.get()
    let menu = [];
     const promises = data.docs.map((doc) =>  // change from forEach to map
            getCategories(doc.id, shop).then(categories =>{
               menu.push({
                menuID: doc.id,
                name: doc.data().name,
                position: doc.data().position,
                categories: categories,
            });
        );

    await  Promise.all(promises);
    return res.json(menu)
  } catch(err) { 
      console.error(err);
      return res.status(500).json({ error: err.message});
    }
}

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

Dealing with asynchronous requests in server-side node applications

Currently, I am in the process of constructing a basic node service that carries out the following functionalities: Handles incoming GET requests from web clients Parses the parameters provided Utilizes these parameters to asynchronously query another RE ...

A runtime error occurred in ScriptResource.axd at line var f = ($telerik.isIE) ? document.createElement('<iframe name="' + this.get_id() + '">');

I am encountering an error during runtime in the ScriptResource.axd file, which is causing a major issue for me as I am unable to modify the code directly to fix it. The error seems to be specific to this line: ScriptResource.axd runtime error on line var ...

Developing a dynamic web application using the Django framework along with the Vue.js library and Highcharts for

I am currently working on a data visualization web app using Django, Highcharts, and JQuery. I have recently transitioned from JQuery to Vue JS and I am struggling with fetching JSON data from a specific URL. Below is the code snippet: Template <!doc ...

Vue.js problem with conditional rendering using v-if

I'm struggling to grasp the concept behind how v-if functions. My goal is to dynamically hide buttons in the navigation bar based on the user's authentication status and current page. Specifically, I want the "My Account" button to be displayed w ...

Execute the function within setInterval only one time

I have a setInterval function that calculates the time difference between a specified date and the current time. Once this difference is less than an hour, I want to execute some code only once. const countdownDate = new Date('March 15, 2021 11:30:00& ...

Using Functional Programming with Node.js: A guide to waiting for a function to complete

As a newcomer to Node.js, I am satisfied with the syntax of JavaScript as I have utilized it for constructing web interfaces. With substantial experience in Object-Oriented Programming from Java and C#, along with an understanding of functional programming ...

I am having trouble getting my "sign in with Google" feature (built with Firebase and React) to work properly after deploying to AWS. What could be causing

I'm in the process of developing a React app integrated with Firebase. My aim is to utilize Firebase's auth features to enable users to sign in using Google credentials. Below is the code snippet I've implemented: <button onClick={h ...

Element that emulates a different element in HTML

Is it possible to have one element that can control and change multiple clone elements, mimicking every change made to the original? While JavaScript & jQuery can easily achieve this, most solutions involve separate variables or instances for each element ...

Verify record removal without a PHP click

My website features a navigation menu that streamlines the browsing experience: <form action="../"> <select onchange="window.open(this.options[this.selectedIndex].value,'_top')"> <option value="" selected="selected">Navigate< ...

Error: In ReactJS, there is an issue where the property 'map' is not defined and cannot be read

I am currently developing an application using expressjs and reactjs. I have successfully retrieved data from the backend using expressjs, but I am encountering an issue with 'map is not a function'. import React, { Component } from "react"; imp ...

Challenges encountered in d3.js when parsing through data sets

For the past two days, I have been struggling to solve this error and I'm at a loss. Every time I try to add data to the visualization, I encounter the following error: Uncaught TypeError: Cannot read property 'length' of undefined It seem ...

Concealed checkbox value in jQuery

I have a problem with setting the hidden checkbox "marketingPhone" to TRUE when the "marketingAAA" checkbox is checked as true. This part works fine. However, if any other checkbox on the page is set to TRUE, then it also sets "marketingPhone" to TRUE. I ...

The button colors in Material Ui do not update properly after switching themes

React Material UI is being utilized in this project. Although the theme is being overridden, the colors of buttons and inputs remain unchanged. Here is how the Material UI theme is created in theme.js // @flow import { createMuiTheme } from '@materi ...

How to retrieve the value of an observable from a regular JavaScript array in Knockout JS?

Context In my project, I am working with a plain JavaScript array that starts off empty but gets populated with Knockout observables later on. These values are numbers and I need to compare them with values in another Knockout observable array. The issue ...

Display exclusively on indexes 0 and 3

Here is the code snippet I am working with: {(type === 'NEW') && ((index === 0) || (index === 3)) && <hr className={styles.hr}/>} I would like to combine these conditions into a single expression that w ...

Why is the size of my array shrinking with every iteration of the for-loop in JavaScript?

I am struggling to change the classname of three elements that share the same classname. Unfortunately, as I loop through my array, it seems to decrease in size with each iteration, preventing me from successfully changing all three elements. Any advice or ...

Tips on extracting the image URL from a canvas element using Selenium in Java and leveraging JavascriptExecutor

My main objective is to extract the image URL from a canvas container. Here is what I have attempted: JavascriptExecutor jse = (JavascriptExecutor) driver; Object imageURL = jse.executeScript("arguments[0].toDataURL('image/png');", canvas); Un ...

Analyzing User Input and Database Information with Mongodb

Here's the HTML form I'm working with: <form id="contact-form" method="POST" action="/search"> <label for="company">Phone company</label> <input type="text" name="company" value=""> &l ...

`Is there a way to retrieve the ID of an element upon clicking on it?`

Can you help me with a JavaScript query? I have two HTML div elements with ids of 'div1' and 'div2'. When I click on any of the divs, I want to display the id of the clicked div. Any thoughts? <div id="div1"></div> <div ...

retrieve information in json format from a specified web address

I need to figure out why the data from a specific URL is not being displayed properly on my node application. It seems like there might be an error in my code. const extractRefDefaultSchema = async (data) => { const url = "https://mos.esante.gouv.f ...