'Sequelize: find count of 3 level associated model entries

I have a products database structure as follows:

Categories > Sub categories > Child categories > Products

the respective table names in mySql database are: categories, subCategories, childCategories and products

My model definitions are as follows:

////////////////// DEFINING ASSOCIATIONS /////////////

/******* CATEGORY - SUBCATEGORY ASSOCIATION *********/

db.category.hasMany(db.subCategory, {
  foreignKey: 'categoryId',
  sourceKey: 'id',
});

db.subCategory.belongsTo(db.category, {
  foreignKey: 'categoryId',
  targetKey: 'id',
});

/******* SUBCATEGORY - CHILDCATEGORY ASSOCIATION *********/

db.subCategory.hasMany(db.childCategory, {
  foreignKey: 'subCategoryId',
  sourceKey: 'id',
});

db.childCategory.belongsTo(db.subCategory, {
  foreignKey: 'subCategoryId',
  targetKey: 'id',
});

/******* CHILDCATEGORY - PRODUCT ASSOCIATION *********/

db.childCategory.hasMany(db.product, {
  foreignKey: 'childCategoryId',
  sourceKey: 'id',
});

db.product.belongsTo(db.childCategory, {
  foreignKey: 'childCategoryId',
  targetKey: 'id',
});

In my summary result, I want to share a table as follows:

expected result picture

For this, I tried multiple variations of the below code but am unable to produce the required result.

My current code to achieve the above result:

exports.getAllCategoriesSummary = async (req, res) => {
  const { page, size, search } = req.query;
  console.log(page, size, search);
  try {
    const totalCategories = await Category.count();
    // get categories and count of included subCategories, childCategories and products
    const [rows, fields] = await mysqlConnPool.promise().execute(
      `SELECT c.id, c.name, COUNT(DISTINCT(s.id)) AS subCategories, 
      COUNT(DISTINCT(ch.id)) AS childCategories, COUNT(p.id) AS products 
      FROM categories c
      LEFT JOIN subCategories s ON c.id = s.categoryId 
      LEFT JOIN childCategories ch ON s.id = ch.subCategoryId 
      LEFT JOIN products p ON ch.id = p.childCategoryId GROUP BY c.id
      ORDER BY c.id ASC LIMIT ${size} OFFSET ${page * size}
      `
    );

    return res.status(200).json({
      status: 'success',
      categories: rows,
      totalCategories: totalCategories,
    });
  } catch (error) {
    return res.status(500).json({
      status: 'error',
      message: error.message,
    });
  }
};

Requesting help to produce the needed result using sequelize.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source