Aggregation with Pagination

Understanding the Problem

When working with paginated data, users often need to know the bigger picture. Imagine reading a book - even when you're on page 50, you want to know how many total pages there are. In our API, we need to provide:

Devising a Plan

  1. Add a count query to get total records
  2. Calculate total pages based on page size
  3. Modify the response structure
  4. Handle error cases with counts
  5. Test with various scenarios

Implementation

Let's implement this step by step in our students endpoint:

Enhanced Implementation (routes/api/students.js)

// GET /students
router.get('/', async (req, res) => {
    // Get pagination parameters
    let page = parseInt(req.query.page) || 1;
    let size = parseInt(req.query.size) || 10;

    // Initialize result object
    const result = {
        rows: [],
        count: 0,
        pageCount: 0,
        page: page
    };

    try {
        // Get total count of students
        const totalCount = await Student.count();
        result.count = totalCount;

        // Calculate total pages
        result.pageCount = Math.ceil(totalCount / size);

        // If valid pagination parameters
        if (page >= 1 && size >= 1 && size <= 200) {
            const offset = (page - 1) * size;
            
            // Get paginated results
            const students = await Student.findAll({
                limit: size,
                offset: offset,
                order: [['lastName', 'ASC'], ['firstName', 'ASC']]
            });

            result.rows = students;
        } else if (page === 0 && size === 0) {
            // Special case: get all results
            const students = await Student.findAll({
                order: [['lastName', 'ASC'], ['firstName', 'ASC']]
            });
            result.rows = students;
            result.page = 1;
        } else {
            // Invalid parameters
            return res.status(400).json({
                errors: [{ message: 'Requires valid page and size params' }],
                count: totalCount,
                pageCount: Math.ceil(totalCount / 10) // Using default size
            });
        }

        return res.json(result);

    } catch (err) {
        console.error(err);
        res.status(500).json({ 
            errors: [{ message: 'Server error' }],
            count: 0,
            pageCount: 0
        });
    }
});
    

Understanding Aggregation

Think of aggregation like taking inventory in a library:

Math Behind Page Count

pageCount = Math.ceil(totalCount / size)

Example calculations:
- 267 total records, 10 per page:
  pageCount = Math.ceil(267 / 10) = 27 pages

- 267 total records, 12 per page:
  pageCount = Math.ceil(267 / 12) = 23 pages

- 267 total records, 150 per page:
  pageCount = Math.ceil(267 / 150) = 2 pages
    

Response Structure

A successful response will look like:

{
    "count": 267,           // Total number of records
    "rows": [...],          // Current page of data
    "pageCount": 27,        // Total number of pages
    "page": 1               // Current page number
}
    

Real World Applications

This pattern appears in many familiar interfaces:

Testing Strategy

Test the following scenarios:

Common Pitfalls

Watch out for these common issues:

Performance Optimization

Consider these optimization techniques:

Debugging Tips

When troubleshooting pagination and aggregation: