Bootcamp
Search…
4.1.9: Sequelize Setup Cheatsheet

How do I know what methods I can call on a given variable?

With Sequelize it can be hard to tell if the associations have been set up correctly. One of the ways the associations are expressed is through the methods you can call on an instance. However, it may not be clear which methods are available, and you cannot see them by simply console.loging the variable.

___proto___

In JavaScript there is an attribute that every value has that specifies things about it's data type. Prototypes and prototype inheritance is out of the scope of what we'll cover, but the __proto__ attribute is where we can access all the available methods.
db.Item = initItemModel(sequelize, Sequelize.DataTypes);
db.Category = initCategoryModel(sequelize, Sequelize.DataTypes);
​
db.Item.belongsToMany(db.Category, { through: 'category_items' });
db.Category.belongsToMany(db.Item, { through: 'category_items' });
​
// get one instance of an item
const item = db.Item.findByPk(12);
​
// see all the association methods for this item instance:
console.log(item.__proto__);

Further Reading on __proto__:

Create a directory for your app and initialize NPM.
npm init -y

Install Sequelize NPM Packages

npm install pg sequelize
npm install --save-dev sequelize-cli

Create Sequelize Folders

mkdir config migrations models seeders

Configure Database

Database Connection Config File Template (config/config.js)

module.exports = {
development: {
username: '<YOUR_UNIX_USER_NAME>',
password: null,
database: '<YOUR_DB_NAME>_development',
host: '127.0.0.1',
dialect: 'postgres',
},
};

Create Database Based on Config

npx sequelize db:create

Migrations

Generate Migration

npx sequelize migration:generate --name create-items-table

Migration File Template

module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('<TABLE_NAME_SNAKE_CASE_PLURAL>', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
<COLUMN_NAME_SNAKE_CASE>: {
type: Sequelize.<COLUMN_DATA_TYPE_UPPERCASE>,
},
// ... [<OTHER_COLUMNS>]
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
​
});
},
​
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('<TABLE_NAME_SNAKE_CASE_PLURAL>');
},
};

Run Migrations

npx sequelize db:migrate

Models

Model File Template (models/<MODEL_NAME_LOWERCASE_SINGULAR>.mjs)

export default function init<MODEL_NAME_UPPER_CAMEL_CASE_SINGULAR>Model(sequelize, DataTypes) {
return sequelize.define('<MODEL_NAME_SNAKE_CASE_SINGULAR>', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
<COLUMN_NAME>: {
type: Sequelize.<COLUMN_DATA_TYPE_UPPERCASE>,
},
// ... [<OTHER_COLUMNS>]
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
}, {
// The underscored option makes Sequelize reference snake_case names in the DB.
underscored: true
});
};

Model Index File Template (models/index.mjs)

import sequelizePackage from 'sequelize';
import allConfig from '../config/config.js';
​
import init<MODEL_NAME_UPPER_CAMEL_CASE_SINGULAR>Model from './<MODEL_NAME_LOWER_CAMEL_CASE_SINGULAR>.mjs';
​
const { Sequelize } = sequelizePackage;
const env = process.env.NODE_ENV || 'development';
const config = allConfig[env];
const db = {};
​
let sequelize = new Sequelize(config.database, config.username, config.password, config);
​
db.<MODEL_NAME_UPPER_CAMEL_CASE_SINGULAR> = init<MODEL_NAME_UPPER_CAMEL_CASE_SINGULAR>Model(sequelize, Sequelize.DataTypes);
​
db.sequelize = sequelize;
db.Sequelize = Sequelize;
​
export default db;

Seeds

npx sequelize seed:generate --name seed-data
npx sequelize db:seed:all

Debug Problems with running the seed data

npx sequelize db:seed:all --debug

Express

index.mjs

import db from './models/index.mjs';

Migrations

Sample Association Migration File (<GENERATED_DATE>-create-categories-items-tables.js)

module.exports = {
up: async (queryInterface, Sequelize) => {
// "categories" table needs to be created first because "items" references "categories".
await queryInterface.createTable('categories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
​
await queryInterface.createTable('items', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
category_id: {
type: Sequelize.INTEGER,
// This links the category_id column to the id column in the categories table
references: {
model: 'categories',
key: 'id',
},
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
​
down: async (queryInterface, Sequelize) => {
// Items table needs to be dropped first because Items references Categories
await queryInterface.dropTable('items');
await queryInterface.dropTable('categories');
},
};

Models

models/category.mjs

export default function initCategoryModel(sequelize, DataTypes) {
return sequelize.define(
'category',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
},
{
// The underscored option makes Sequelize reference snake_case names in the DB.
underscored: true,
}
);
}

models/item.mjs

export default function initItemModel(sequelize, DataTypes) {
return sequelize.define(
'item',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
},
categoryId: {
type: DataTypes.INTEGER,
// This links the categoryId column to the id column in the categories table
references: {
model: 'categories',
key: 'id',
},
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
},
{
// The underscored option makes Sequelize reference snake_case names in the DB.
underscored: true,
}
);
}

models/index.mjs

import initItemModel from './item.mjs';
import initCategoryModel from './category.mjs';
​
// ... other things
​
db.Item = initItemModel(sequelize, Sequelize.DataTypes);
db.Category = initCategoryModel(sequelize, Sequelize.DataTypes);
​
db.Item.belongsTo(db.Category);
db.Category.hasMany(db.Item);
​
// ...

Migrations

Sample Migration File (<GENERATED_DATE>-create-categories-items-tables.js)

module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('categories', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
​
await queryInterface.createTable('items', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name: {
type: Sequelize.STRING,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
await queryInterface.createTable('category_items', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
category_id: {
type: Sequelize.INTEGER,
references: {
model: 'categories',
key: 'id',
},
},
item_id: {
type: Sequelize.INTEGER,
references: {
model: 'items',
key: 'id',
},
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
​
down: async (queryInterface, Sequelize) => {
// Drop category_items first because it references items and categories.
await queryInterface.dropTable('category_items');
await queryInterface.dropTable('items');
await queryInterface.dropTable('categories');
},
};

Models

models/category.mjs

export default function initCategoryModel(sequelize, DataTypes) {
return sequelize.define(
'category',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
},
{
// The underscored option makes Sequelize reference snake_case names in the DB.
underscored: true,
}
);
}

models/item.mjs

export default function initItemModel(sequelize, DataTypes) {
return sequelize.define(
'item',
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
name: {
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
},
{
// The underscored option makes Sequelize reference snake_case names in the DB.
underscored: true,
}
);
}

models/index.mjs

import initItemModel from './item.mjs';
import initCategoryModel from './category.mjs';
​
// ... other stuff
​
db.Item = initItemModel(sequelize, Sequelize.DataTypes);
db.Category = initCategoryModel(sequelize, Sequelize.DataTypes);
​
db.Item.belongsToMany(db.Category, { through: 'category_items' });
db.Category.belongsToMany(db.Item, { through: 'category_items' });
​
// ...