Sequelize Lazy Loading and Aggregate Data

Understanding the Problem

We need to implement three Express routes that handle aggregated data from a database containing cats and toys:

  1. Get summary statistics for all toys (count, min/max/total price)
  2. Get a cat with its toys and toy statistics (count, total price, average price)
  3. Get a toy with its cats and calculate orange cat percentage

Devising a Plan

  1. For /toys-summary:
  2. For /cats/:catId:
  3. For /toys/:toyId (bonus):

Implementing the Solution

Step 1: Toy Summary Statistics


// GET /toys-summary
app.get('/toys-summary', async (req, res, next) => {
    // Get total count of toys
    const count = await Toy.count();

    // Find minimum price across all toys
    const minPrice = await Toy.min('price');

    // Find maximum price across all toys
    const maxPrice = await Toy.max('price');

    // Calculate sum of all toy prices
    const sumPrice = await Toy.sum('price');

    res.json({
        count,
        minPrice, 
        maxPrice,
        sumPrice
    });
});
    

Step 2: Cat with Toy Statistics


// GET /cats/:catId
app.get('/cats/:catId', async (req, res, next) => {
    const { catId } = req.params;

    // Find cat and eagerly load associated toys
    const cat = await Cat.findByPk(catId, {
        include: { model: Toy }
    });

    const toys = cat.Toys;

    // Calculate toy statistics using array methods
    const toyCount = toys.length;
    
    const toyTotalPrice = toys.reduce((sum, toy) => {
        return sum + toy.price;
    }, 0);

    const toyAvgPrice = Math.round(toyTotalPrice / toyCount);

    res.json({
        toyCount,
        toyTotalPrice,
        toyAvgPrice,
        ...cat.toJSON()
    });
});
    

Step 3: Toy with Cat Statistics (Bonus)


// GET /toys/:toyId
app.get('/toys/:toyId', async (req, res, next) => {
    const { toyId } = req.params;

    // Find toy and eagerly load associated cats
    const toy = await Toy.findByPk(toyId, {
        include: { model: Cat }
    });

    const cats = toy.Cats;
    
    // Calculate cat statistics
    const catCount = cats.length;
    
    const orangeCatCount = cats.filter(cat => 
        cat.color === 'Orange'
    ).length;

    // Calculate percentage with rounding
    const orangeCatPercentage = Math.round(
        (orangeCatCount / catCount) * 100
    ) + '%';

    res.json({
        catCount,
        orangeCatCount,
        orangeCatPercentage,
        ...toy.toJSON()
    });
});
    

Understanding the Code

Sequelize Aggregate Methods

Sequelize provides built-in methods for common database aggregations:

Eager Loading vs Calculating in JavaScript

There are two main approaches to getting aggregate data:

  1. Database Aggregation: Using Sequelize aggregate methods that execute SQL aggregations
  2. JavaScript Calculation: Loading the data and calculating statistics in memory

For small datasets, JavaScript calculations can be simpler and more flexible. For large datasets, database aggregations are more efficient.

The toJSON() Method

When working with Sequelize models, toJSON() converts the model instance into a plain JavaScript object. This is important for:

Real World Example

Think of this like an e-commerce system:

Common Pitfalls

Best Practices