0

I'm trying to construct an array of objects and render them using ejs. The objects array is coming from the database from a table called products. I was able to run a query and get the products data but I need to run a nested query on each product using the category id of the products to get other info like category name (in another table). I tried using a foreach loop on every product and run a nested query but the problem is since the nested queries in foreach loop is done asynchronously, I can't serve the data from outside the foreach.

Is there a way to run multiple queries and save the data to a variable and serve that variable from outside the query callback?

part of my code

database.con.query('SELECT * FROM products', (err, products) => {
if(err) throw err;
let productsArr = products; // productsArr will hold all data to be rendered
productsArr.forEach((product, index) => {

  database.con.query(`SELECT * FROM category WHERE Id = ${product.Category_id}`, (err, category) => {
    if(err) throw err;
    productsArr[index].cat = category[0]; // Save the categories of each product as a property
  }); // End of nested query

});// End of foreach

res.render('products/index.ejs', {products: productsArr}); // 'productsArr' have all products data but not the categories (cat propery) of each product
});

Note: I could run a joined query to get all the data in one go but I need to know how to fix it using the above method for other reasons

I hope I'm making sense with my broken English. Any help is appreciated

4
  • One possible way: Promise.all() Some code from you would be helpfull Commented Nov 24, 2020 at 11:42
  • code added @Marc Commented Nov 24, 2020 at 12:09
  • I tried using array.map instead of foreach and return a promise for each query then, resolved all promises using Promise.all(). Though the whole thing looks messy now but that have worked. Thank you @Marc Commented Nov 24, 2020 at 12:54
  • Thats exacty what i put for you together right now. should i post my answer or are you good ? Commented Nov 24, 2020 at 12:58

1 Answer 1

1

I thought of somehting like this: (Note: not tested)

database.con.query('SELECT * FROM products', (err, products) => {

    if (err) throw err;

    let wrapper = products.map((product) => {
        return new Promise((resolve, reject) => {

            database.con.query(`SELECT * FROM category WHERE Id = ${product.Category_id}`, (err, category) => {
                if (err) {

                    reject(err);

                } else {

                    resolve(category[0]);

                };
            });

        });
    });


    Promise.all(all).then((results) => {

        let arr = products.map((product, index) => {
            product.cat = results[index];
            return product;
        });

        res.render('products/index.ejs', {
            products: arr
        });

    }).catch((err) => {

        console.error(err);

    });



});
Sign up to request clarification or add additional context in comments.

2 Comments

That is what I tried based on your comment and it worked. One thing though, wrapper will be an array of promises so we need Promise.all(wrapper).then(whatever) to handle them which is what you mentioned in your comment. Thank you for your help @Marc
Yeah, your right. In the heat of the moment and without testing, this kind of mistakes happen ;) Fixed it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.