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:

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:

However, the log displays this:

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

How can I retrieve the reference number of an item by clicking a button within a list item in an unordered

Presented here is a collection of data points and a button nested within an ul <ul> <li class="mix" category-1="" data-value="600.35" style="display:block;"> <figure> <figcaption> <h3> ...

Utilizing the default event object in ag-Grid's event methods with JavaScript

I am a newcomer to ag-grid and I need help with calling event.preventDefault() in the "cellEditingStopped" grid event. Unfortunately, I am struggling to pass the default JavaScript event object into it. Is there a way to make this work? Additionally, I al ...

Tips for organizing an API response based on a specific field

I'm currently in the process of learning Reactjs and I've hit a roadblock with a specific question. I have successfully fetched data using axios from an API endpoint (such as countries with details like population, currencies, region, etc.) and n ...

Encountering an unexpected token while trying to use createUserWithEmailAndPassword in firebase/auth with Next.js and TypeScript left Jest puzzled

I have been working on integrating Firebase authentication into my Next.js project (using TypeScript), but it appears that there are configuration issues with Firebase causing my Jest tests to fail. Here are the key configuration files: jest.config.js : ...

Trigger a function when the browser automatically populates an input field

I am attempting to trigger a function that can detect if the browser has autofilled a field and then add a specific class to it. After finding a thread with a solution that mostly works, mentioned here: Here is how I implemented it: $.fn.allchange = fun ...

The HTTP request is being executed twice for some reason unknown to me

import React, {useState, useEffect} from 'react' export function UseStateExample() { // This is a named export that must be used consistently with {} when importing/exporting. const [resourceType, setResourceType] = useState(null) useEffect ...

Leveraging Mongodb's aggregate feature to calculate the overall quantity of a specific product that has been ordered across all

Recently delving into the realm of javascript, I am currently tackling a dashboard project that requires displaying the total quantity of each product ordered. Although I have successfully defined a variable 'qty' to represent the quantity of an ...

Retrieve the URL with a GET request and remove a specific object

Currently, I am working on developing a CRUD (Create, Read, Update, Delete) App using Express and LowDB. So far, I have successfully implemented the create and read functions, but I am facing issues with the delete function. This is an example of what th ...

Guide on retrieving information from MySQL database and showcasing it in a form through AJAX

I have developed a form that is designed to automatically populate the fields for first name and last name with data from mysql when the user enters their user_id. My approach involves using ajax to retrieve the data, which works fine as I am able to fetch ...

Maximizing the potential of Angular forms through native FormData

Currently, I am revisiting an older project that still uses traditional methods for form submission. The HTML includes a form element with defined method and action. My goal is to submit the form in the old-fashioned way using the action attribute to post ...

JavaScript program that continuously reads and retrieves the most recent data from a dynamically updating JSON file at regular intervals of every few seconds

I am a beginner in JavaScript and I'm facing an issue with displaying the most recent values from a .json file on an HTML page. The file is updated every 10 seconds, and I am also reading it every 10 seconds, but I'm not getting the latest data. ...

Exploring the Benefits of Implementing Etag in Sails.js

Currently, I am seeking ways to enhance the cache capabilities of my Sails application. Sails generates an Etag with its response. However, despite sending a GET request with an 'if-None-Match' header containing the Etag from the previous respon ...

not capable of outputting findings in a sequential manner

I am encountering an issue where my result is not printing line by line, instead everything shows up on a single line. How can I resolve this problem? Here is the code snippet I have tried: <script> function know(){ var num = Number(doc ...

The image component is missing the necessary "src" attribute even though a valid src value has been provided as a prop

I'm encountering an issue in Next.JS where a component is not recognizing the image source passed through a prop. I am providing the path of an image named "logo.jpg" from the project's public folder. The image successfully displays when used as ...

Filtering properties of objects in Vue

I am currently dealing with an array of objects that represent continents: data() { return { continents: [ { name: "South America", countries: [ { name: "P ...

The post() method in Express JS is functioning flawlessly in Firebase cloud function after deployment, however, it seems to encounter issues when running on a

https://i.stack.imgur.com/bIbOD.pngI am facing an issue with my Express JS application. Despite having both post() and get() requests, the post() request is not working on my local machine. It keeps throwing a 404 error with the message "Cannot POST / ...

Limiting the DatePicker in React JS to only display the current year: Tips and Tricks!

I'm currently implementing the KeyboardDatePicker component in my React application to allow users to choose a travel date. However, I am looking to restrict the date selection to only the current year. This means that users should not be able to pick ...

Is it feasible to utilize the HTML5 video tag in conjunction with a JSON callback?

Curious about the possibility of a video page layout featuring a main screen and smaller clickable screens below it. When clicking on one of the smaller screens, the main screen would display the selected video, similar to YouTube. We have obtained data f ...

Node.js - CSRF Protection Token Undefined

I've been facing challenges with setting up CSRF token generation, and I seem to be missing something. server.js: // configuration ====================================================================== var express = require('express'); va ...

When attempting to toggle the view on button click, it is not possible to select a shadowRoot

I am facing an issue with my parent component named ha-config-user-picker.js and its child component called edit-user-view.js. Parent Component: It contains a mapping of users and includes the child component tag along with its props. When a click event i ...