Giter Club home page Giter Club logo

u3_lesson_sequelize_associations's Introduction

Sequelize Associations

Overview

In this lesson, we'll be covering how to build associations bewteen differen models/tables. We'll set up foreign keys and execute queries to include the related data. Associations are one of the most important topics we'll cover when it comes to relational databases as they are the principles that make relational databases as popular as they are.

Getting started

  • Fork and Clone
  • npm install
  • sequelize db:create

Take five minutes and read the Sequelize docs on associations:

What Are Associations

Associations are the relationships that we define between different data entries accross different tables. For example:

  • A user can have many pets
  • Pets belong to one user

Relational databases rely on associations in order to join data that we need in a an organized manner. It also helps reduce database load. Databases can become overwhelmed when being queried repeatedly in a short amount of time. By joining data, we can load all of the data we need with one query.

Defining Models

Defining Our User

Let's start with building a User model:

sequelize model:generate --name User --attributes firstName:string,lastName:string,password:string,email:string

The above command will generate the following model:

'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
    }
  }
  User.init(
    {
      firstName: DataTypes.STRING,
      lastName: DataTypes.STRING,
      password: DataTypes.STRING,
      email: DataTypes.STRING
    },
    {
      sequelize,
      modelName: 'User'
    }
  )
  return User
}

Let's update the User model to have a lowercased tableName

...

    {
      sequelize,
      modelName: 'User',
      tableName: 'users'
    }

...

Next we'll need to update our migration to reflect our desired tableName:

'use strict'
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      firstName: {
        type: Sequelize.STRING
      },
      lastName: {
        type: Sequelize.STRING
      },
      password: {
        type: Sequelize.STRING
      },
      email: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    })
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('users')
  }
}

You can now execute the migration:

sequelize db:migrate

Defining A Task Model

Let's start by creating a task model:

sequelize model:generate --name Task --attributes title:string,userId:integer

The above command will generate the following model:

'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
  class Task extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
    }
  }
  Task.init(
    {
      title: DataTypes.STRING,
      userId: DataTypes.INTEGER
    },
    {
      sequelize,
      modelName: 'Task'
    }
  )
  return Task
}

Let's update the table name for our Task:

...

    {
      sequelize,
      modelName: 'Task',
      tableName: 'tasks'
    }

...

Associating Models

We'll now associate the User and Task model. The relationship we want to define is a hasMany/belongsTo:

  • User hasMany Task
  • Task belongsTo User

Now, you may be thinking that this is a complicated process... Believe it or not, it isn't! Sequelize models actually have built in methods that make it easy to associate our created models!

Defining hasMany

In your User model, we'll attach a method that will tell Sequelize in what direction our association flows. Find the static associate(models) method in the User model.

We'll now define our hasMany relationship:

class User extends Model {
  /**
   * Helper method for defining associations.
   * This method is not a part of Sequelize lifecycle.
   * The `models/index` file will call this method automatically.
   */
  static associate(models) {
    // define association here
    User.hasMany(models.Task, { foreignKey: 'userId' })
  }
}

Here's a quick breakdown on how this works:

Defining belongsTo

Now we'll associate our Task to our user.

Let's add a belongsTo method to the Task model:

class Task extends Model {
  /**
   * Helper method for defining associations.
   * This method is not a part of Sequelize lifecycle.
   * The `models/index` file will call this method automatically.
   */
  static associate(models) {
    // define association here
    Task.belongsTo(models.User, { foreignKey: 'userId' })
  }
}

The belongsTo method works the same way as the hasMany method except that we are telling Sequelize that the Task belongs to a User.

Next we'll need to update the userId field to declare it as a foreign key:

Task.init(
  {
    title: DataTypes.STRING,
    userId: {
      type: DataTypes.INTEGER,
      onDelete: 'CASCADE',
      references: {
        model: 'users',
        key: 'id'
      }
    }
  },
  {
    sequelize,
    modelName: 'Task',
    tableName: 'tasks'
  }
)

Here's a quick breakdown on what we did to the userId field:

Now we need to reflect this change in the Task migration:

'use strict'
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('tasks', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      title: {
        type: Sequelize.STRING
      },
      userId: {
        type: Sequelize.INTEGER,
        onDelete: 'CASCADE',
        references: {
          model: 'users',
          key: 'id'
        }
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    })
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('tasks')
  }
}

Note: Make sure to update the table name for Task!

Querying Associations

Now that we've defined our associations, we're ready to finish migrating our database. Run the following command to execute the Task migration:

sequelize db:migrate

Next we'll create a seed file to execute some queries:

sequelize seed:generate --name task

Replace the contents of the seed file with the following:

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert(
      'tasks',
      [
        {
          title: 'Build an App.',
          userId: 1,
          createdAt: new Date(),
          updatedAt: new Date()
        }
      ],
      {}
    )
  },

  down: (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('tasks', null, {})
  }
}

We can now run the seed files:

sequelize-cli db:seed:all

Let's see if our associations actually work. We'll run a join query on our User table:

psql sequelize_associations_development
SELECT * FROM users JOIN tasks ON tasks."userId" = users.id;

Querying

Utilizing the Sequelize Docs, write two queries that match their provided SQL statements. The functions have been provided for you in query.js To run your file, execute:

node query.js

Recap

In this lesson, we learned how to define and query associations. Associations are an important concept in the relational database world and are a core fundamental to what makes these databases so powerful.

Resources

u3_lesson_sequelize_associations's People

Contributors

brunopgalvao avatar anpato avatar ahonore42 avatar nobodyslackey avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.