Bootcamp
Search…
4.1.7: Sequelize Eager Loading

Introduction

In Modules 4.1.2: Sequelize 1-M Relationships and 4.1.4: Sequelize M-M Relationships we learned how to access associated data via Sequelize getter and setter methods. Typically we would do this sequentially, e.g. retrieve an item, then use a getter method to get all of its categories. Sequelize provides a way called "eager loading" to retrieve this data all at once, which uses join queries under the hood. This is helpful when we know we need certain data upfront. See more on eager loading syntax here.
This module assumes the set of models we used in 4.1.5: Sequelize M-M with Non-FK Attributes in Through Table.

get_categories.mjs

This is a command-line Node script. Run using the node command on command line. Using eager loading we can get the 1st item in the 1st cart with a single findAll query. include gives us the ability to retrieve any set of associated models. See eager loading docs on different ways of performing eager loading in Sequelize.
import db from './models/index.mjs';
​
const getEagerLoadedModels = async () => {
try {
const carts = await db.Cart.findAll({ include: db.Item });
console.log(carts[0].items[0].name);
} catch (error) {
console.log(error);
}
};
​
getEagerLoadedModels();

Sample Command

node get.mjs

Sample Output

canned

get_cart_items.mjs

import db from './models/index.mjs';
​
const getEagerLoadedModels = async () => {
try {
const carts = await db.Cart.findAll({
include: {
model: db.Item,
include: [db.Category, db.CartItem],
},
});
​
// get the quantity of items in the cart
console.log(carts[0].items[0].cart_items[0].quantity);
} catch (error) {
console.log(error);
}
};
​
getEagerLoadedModels();

Why eager loading?

We should utilize eager loading, whenever we need all our related data at once. By using eager loading we would reduce the amount of times we query the database.
Let us look at the following example, where we would retrieve all carts first, and afterwards check if each cart has an item to decide if we want to send email:
const carts = await db.Cart.findAll();
​
carts.forEach((cart) => {
const hasItem = db.Item.findOne({
where: {
cart_id: cart.id
}
})
​
if (hasItem) {
sendEmail();
}
})
For the above example, let us assume we have 1000 carts. That would mean, we would query the db once for all carts, and make 1000 db queries, to check if each cart has an item. This would result in 1001 db queries in total, which obviously is inefficient.
By using eager loading, we can reduce this to a single database query and make our code far more efficient and more scalable:
const carts = await db.Cart.findAll({ include: [db.Item] });
​
carts.forEach((cart) => {
const hasItem = cart.Items.length > 0;
​
if (hasItem) {
sendEmail();
}
})
In the ideal case scenario, we should always think about performance when using loops, .forEach() or .map() methods.