Skip to content

Instantly share code, notes, and snippets.

@zcaceres
Last active July 27, 2024 13:21
Show Gist options
  • Save zcaceres/83b554ee08726a734088d90d455bc566 to your computer and use it in GitHub Desktop.
Save zcaceres/83b554ee08726a734088d90d455bc566 to your computer and use it in GitHub Desktop.
using Include in sequelize

'Include' in Sequelize: The One Confusing Query That You Should Memorize

When querying your database in Sequelize, you'll often want data associated with a particular model which isn't in the model's table directly. This data is usually typically associated through join tables (e.g. a 'hasMany' or 'belongsToMany' association), or a foreign key (e.g. a 'hasOne' or 'belongsTo' association).

When you query, you'll receive just the rows you've looked for. With eager loading, you'll also get any associated data. For some reason, I can never remember the proper way to do eager loading when writing my Sequelize queries. I've seen others struggle with the same thing.

Eager loading is confusing because the 'include' that is uses has unfamiliar fields is set in an array rather than just an object.

So let's go through the one query that's worth memorizing to handle your eager loading.

The Basic Query

Here's how you would find all the rows of a particular model without eager loading.

Albums.findAll()
.then(albums => console.log(albums))
.catch(console.error)

Vanilla Include

Here's how you would find all the Artists associated with your albums.

Albums.findAll({
  include: [{// Notice `include` takes an ARRAY
    model: Artists
  }]
})
.then(albums => console.log(albums))
.catch(console.error)

This will take you a long way. Sequelize is smart enough to pull in any rows from your Artists model that are associated with your Albums.

Include takes an array of objects. These objects have properties like model, as, and where which tell Sequelize how to look for associated rows.

Customized Include with an Alias

Now, let's customize how we receive our eagerly-loaded rows.

Albums.findAll({
  include: [{
    model: Artists,
    as: 'Singer' // specifies how we want to be able to access our joined rows on the returned data
  }]
})
.then(albums => console.log(albums))
.catch(console.error)

In this query, we have specified that the instances we receive back from Sequelize should have a property called 'Singer'. We'll be able to access any rows from our Artists table associated with our Albums through this .Singer property.

Customized Include with Alias and Where

Finally, let's layer a where onto our include, so we can narrow down the rows that we'll receive.

Albums.findAll({
  include: [{
    model: Artists,
    as: 'Singer',
    where: { name: 'Al Green' } //
  }]
})
.then(albums => console.log(albums))
.catch(console.error)

Our where query should look familiar if you've used Sequelize before: it has the same format as any typical Sequelize query. Our query will now only return joined rows where 'Al Green' is the name of the associated artist. We can access Al Green's artist data for relevant Album instances on our aliased .Singer property.

To wrap up, include takes an array of objects. These objects are queries of their own, essentially just Sequelize queries within our main query. Inside each include query we specify the associated model, narrow our results with where, and alias our returned rows with as. Memorizing model, where, as, and that include takes an array will make your next experience with eager loading much more pleasant.

@TamimEhsan
Copy link

How can I remove nesting when including columns from multiple table?
raw: true
option gives something like Model_name.column_name, But I want just column_name
image
How can I just get autor_id from here?

@fasikaWalle
Copy link

fasikaWalle commented Mar 18, 2021

Thank you

@ajbraus
Copy link

ajbraus commented Mar 28, 2021

What about if the foreign key is different from the associated model name. E.g. I have a Trip model with a destinationId and a originId columns that both associate with a City model. So how do I include the destination and the origin of the trip. i.e. two city records?

@ricardoscotti
Copy link

ricardoscotti commented May 28, 2021

Hello,

I have a get with sequelize, which I'm using an include, as an association is being made, and the returning is coming as:

{"nome": "digao", "nota": 10}
{"nome": "digao", "nota": 9}

but, I would need it to be returned as

{
“nome”: “digao”,
“notas”: [{“nota”: 9},{“nota”: 10}]
}

Any ideas how could I normalize it?
Any tought is highly appreciated

@KOD3X
Copy link

KOD3X commented Jun 8, 2021

hello, I have the following problem, I have the people model that indicates the role of a person in a project, when I try to use the include I get an error. Please i need help.

module.exports = (sequelize, type) => {
    return sequelize.define("people", {
        userId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "users",
                key: "id",
            },
        },
        rolId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "roles",
                key: "id",
            },
        },
        projectId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "projects",
                key: "id",
            },
        },
    });
};

and I am trying to do this:

const test = await People.findAll({
        where: {
            userId: req.userId,
        },
        include: [
            {
                model: Project,
            },
        ],
    });
    console.log(test);

but I'm getting this error:

(node:3952) UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: project is not associated to people!

is it required to use the belongsTo?

@GioAceto
Copy link

Thank you, this was very helpful.

@dvalley56
Copy link

I have one product table and another is stock of products table but i am getting this result by joining these both tables using "include", I want both table's specific attributes in one object how can I do that please help. Thanks in advance
"data": [
{
"id": 1,
"product_id": 1,
"product_code": "sun1200",
"stock_quantity": 1200,
"is_del": 0,
"created_by": 1,
"modified_by": null,
"createdAt": "2019-02-24T16:40:17.000Z",
"updatedAt": null,
"product": {
"id": 1,
"product_name": "Sun-Glass",
"product_code": "sun1200",
"mrp_price": 120000,
"product_img": "",
"discount": 2000,
"category": "eye-glass",
"subcategory": "eye-glass",
"model_no": "sunglass1222",
"tax": 20,
"created_by": 1,
"modified_by": null,
"createdAt": "2019-01-19T13:30:25.000Z",
"updatedAt": "2019-01-19T13:30:25.000Z"
}
}
]

Hello mate, I myself want something like this, did you find any solution?

@lexyfeitopayrix
Copy link

This doesnt seem to be working when using association instead of model

[{ association: 'relatedUser', as: 'user' }]

anyone knows if this is possible?

@imongault
Copy link

very helpful btw

@AnkurBansal18
Copy link

hello, I have the following problem, I have the people model that indicates the role of a person in a project, when I try to use the include I get an error. Please i need help.

module.exports = (sequelize, type) => {
    return sequelize.define("people", {
        userId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "users",
                key: "id",
            },
        },
        rolId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "roles",
                key: "id",
            },
        },
        projectId: {
            type: type.INTEGER,
            allowNull: false,
            primaryKey: true,
            onDelete: "CASCADE",
            references: {
                model: "projects",
                key: "id",
            },
        },
    });
};

and I am trying to do this:

const test = await People.findAll({
        where: {
            userId: req.userId,
        },
        include: [
            {
                model: Project,
            },
        ],
    });
    console.log(test);

but I'm getting this error:

(node:3952) UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: project is not associated to people!

is it required to use the belongsTo?

Yes, you need to define a association between people and project model to use include in sequelize.

@dvalley56
Copy link

dvalley56 commented Aug 6, 2022

Anyone who is still struggling with this;

See below example
Assume two models Student and College

Student -> id (PK), name, rollNo
College-> id (PK), name

Relations

Student.belongsTo(College, {
    foreignKey: {
        name: 'collegeId'
    }
})   //ThIs will create a column studentId in College

College.hasMany(Student, {
    foreignKey: 'collegeId'
}) //I will explain below in which case this is required

Making a query

Including College in Student

1 )

Student.findOne({
    where: {
      id: 1  
    },
    include: [{
        model: College
   }]
})

This will return something like this;

{
   "id": 1,
   "name":  "John Doe",
   "College": {
        "id": 5,
        "name": "My College"
   }
}
Student.findOne({
    where: {
      id: 1  
    },
    attributes: [
         [sequelize.col("Student.name", "id")]
          [sequelize.col("Student.name", "name")]
         [sequelize.col("College.name", "collegeName")]
    ],
    include: [{
        model: College
   }]
})

Note
Below code will give ambiguous column name in our scenario, so we have to specify explicitly.

    attributes: [
         'id',
         'name',
         [sequelize.col("College.name", "collegeName")]
    ],

This will return something like this;

{
   "id": 1,
   "name":  "John Doe",
   "collegeName" : "My College"
}

Including Student in College
This is where we require the hasMany association

1 )

College.findOne({
    where: {
      id: 5 
    },
    include: [{
        model: Student
   }]
})

This will return something like this;

{
   "id":  5,
   "name":  "My College",
   "Students": [{
        "id": 1,
        "name": "John Doe"
   }]
}

Note the array in Students

By using hasOne association, we can get only one student with college, depends on what you want to achieve.

I have tried to explain my best; if there is anything I missed, then correct me 😊.
This code is written without running it, but the association is same as mentioned.

@GunjanRajTiwari
Copy link

How can I include just the number of artists?

@anupamtechsimians
Copy link

i am shocked..
does includes perform a lot of subquerys.??

this is the query let include = include_program?[ { model: Program, as: "programs", attributes: [ 'id',"program_name" ],required: false, limit:2, }]:[] const instituteSchema = await Institute.findAndCountAll({where:whereCriteria, include,limit,offset:start });

sequelize performs this query.. SELECT "programs".* FROM (SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10001 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10002 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10003 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10004 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10051 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10052 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10054 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10053 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10055 LIMIT 2) AS sub UNION ALL SELECT * FROM (SELECT "id", "program_name", "college_id" FROM "programs" AS "programs" WHERE "programs"."college_id" = 10056 LIMIT 2) AS sub) AS "programs";

here is association
Institutes.hasMany(Programs, { foreignKey: 'college_id', as: 'programs' });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment