Sequelize.js: How to Use Include with Attributes

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

Overview

Sequelize is a powerful Object-Relational Mapping (ORM) library for Node.js. It provides a high-level abstraction for dealing with database operations, allowing developers to write less SQL and instead interact with database resources as JavaScript objects. A key feature of Sequelize is its support for eager loading associated models using the include option. This tutorial will walk you through using include together with attributes to fine-tune the results of your database queries, enhance performance, and manage data retrieval with precision.

Basic Usage of Include

To start off, let’s look at a simple case where we have two models, User and Post, and we want to fetch users along with their posts. Here’s how you’d do it:

const users = await User.findAll({
  include: [{
    model: Post
  }]
});

With the above code, Sequelize will return all users along with all their posts. This includes all columns in the Post model by default.

Specifying Attributes in Include

Now, what if you only want to include certain attributes from the associated Post model? You can specify them like this:

const users = await User.findAll({
  include: [{
    model: Post,
    attributes: ['title', 'createdAt']
  }]
});

With this modification, Sequelize will only fetch the title and createdAt columns from the Post table, alongside all attributes from the User table.

Working with Nested Includes

Sometimes your model associations can be more complex, involving nested relations. Consider the example where Post also has a Comment model associated with it:

const users = await User.findAll({
  include: [
    {
      model: Post,
      attributes: ['title'],
      include: [{
        model: Comment,
        attributes: ['content', 'createdAt']
      }]
    }
  ]
});

This will gather users, their selected post attributes (in this case, just the title), and the specified attributes from their comments.

Attribute Exclusion and Renaming

Sequelize also offers flexibility in excluding attributes or renaming them in the result set. To exclude certain attributes, you can use the option exclude:

const users = await User.findAll({
  attributes: { exclude: ['password'] },
  include: [{
    model: Post,
    attributes: { exclude: ['content'] }
  }]
});

To rename an attribute, you can use Sequelize’s literal function:

const users = await User.findAll({
  attributes: [['firstName', 'first_name'], 'lastName'],
  include: [{
    model: Post,
    attributes: [[Sequelize.literal('`Post`.`title`'), 'post_title']]
  }]
});

This will return users with their first names aliased to first_name and their last names. In the posts, the title will be aliased to post_title.

Advanced Attribute Functions and Aggregation

Sequelize’s real power is revealed when you combine includes with Sequelize’s functions and aggregation capabilities. Suppose you want to include the count of posts for each user:

const users = await User.findAll({
  attributes: {
    include: [
      [Sequelize.fn('COUNT', Sequelize.col('posts.id')), 'postCount']
    ]
  },
  include: [{
    model: Post,
    attributes: []
  }],
  group: ['User.id']
});

By passing an empty array to attributes in the Post include, you instruct Sequelize not to fetch any specific columns from the Post table, thus optimizing the query.

Conclusion

In conclusion, Sequelize’s include functionality paired with attributes gives you immense control over the data you fetch from your relational databases. Understanding and using these concepts effectively can help optimize your queries, reduce the amount of data transfer, and structure your API responses more efficiently. As a best practice, always be mindful of what data you need and tailor your includes and attributes to suit those needs.