Understanding GROUP BY in Sequelize.js

Updated: December 29, 2023 By: Guest Contributor Post a comment

Introduction

Sequelize is a promise-based Node.js ORM (Object-Relational Mapping) for Postgres, MySQL, MariaDB, SQLite, and Microsoft SQL Server. It features robust transaction support, eager and lazy loading, read replication, and more. GROUP BY is an SQL statement used in conjunction with aggregate functions to group the result-set by one or more columns. This article aims to elucidate the use of the GROUP BY feature within Sequelize.js through progressive examples.

Basic Usage of GROUP BY

The most straightforward way to use GROUP BY in Sequelize is to specify the attributes you want to group by in the group option of a query. Here’s a simple example grouping users by their role:

const User = sequelize.define('user', {
  username: Sequelize.STRING,
  role: Sequelize.STRING
});

User.findAll({
  attributes: ['role'],
  group: ['role']
}).then(groups => {
  console.log(groups);
});

This will produce an output of users grouped by their different roles.

Grouping with Aggregate Functions

Often you need to perform calculations on grouped data using aggregate functions like COUNT, SUM, AVG, etc. Sequelize makes this convenient with its function methods. Here is how you can count the number of users within each role:

const Sequelize = require('sequelize');
const Op = Sequelize.Op;

User.findAll({
  attributes: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'userCount']],
  group : ['role'],
  order: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'DESC']]
}).then(result => {
  console.log(result);
});

The resulting output will provide a count of users for each role, ordered in descending fashion.

Advanced GROUP BY: Joining Tables

When working with related tables, you might want to group data across these relationships. Sequelize offers a powerful way to join tables and group results. Here’s an example where we join a ‘posts’ table to a ‘users’ table and count the number of posts by user:

const Post = sequelize.define('post', {/* ... */});
User.hasMany(Post, { foreignKey: 'userId' });

User.findAll({
  attributes: [
    'username',
    [Sequelize.fn('COUNT', Sequelize.col('posts.id')), 'postCount']
  ],
  include: [{
    model: Post,
    attributes: []
  }],
  group: ['user.id'],
  order: [[Sequelize.fn('COUNT', Sequelize.col('posts.id')), 'DESC']]
}).then(result => {
  console.log(result);
});

In this join, the posts are counted for each user and the result is sorted based on the post count.

Handling GROUP BY with Having

The HAVING clause in SQL is used to specify a search condition for a group. In Sequelize, you can utilise the having option to filter the groups. The following example filters all roles that have a user count greater than 10:

User.findAll({
  attributes: [
    'role',
    [Sequelize.fn('COUNT', Sequelize.col('*')), 'userCount']
  ],
  group: 'role',
  having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col('*')), '>', 10)
}).then(result => {
  console.log(result);
});

This will return only those roles with more than 10 users associated.

Conclusion

GROUP BY in Sequelize is a flexible and powerful tool that, when combined with aggregate functions, can provide insightful data summaries. As shown in the examples above, you can group your results by one or more fields, compute aggregates like counts, sums, and averages, and even filter groups with the HAVING statement. Understanding GROUP BY will certainly enhance your ability to manipulate and interpret your data effectively using Sequelize.