Sequelize로 Foreign Key, Relationship 설정하기

janghoosa·2022년 8월 30일
0

Node.js

목록 보기
3/4
post-thumbnail
post-custom-banner

Sequelize란?

Sequelize는 TypeScript와 Node.js에서 ORM(Object Relation Mapping)을 사용하게 해주는 라이브러리이다.
자바스크립트의 객체와 관계형 데이터베이스를 서로 연결해주어 DB작업을 더 쉽게 할 수 있도록 도와준다.

Sequelize 사용법

sequelize 설치

sequelize와 sequelize를 편하게 사용하게 해주는 명렁어 라이브러리인 sequelize-cli, MySQL 서버와 연결해주는 mysql2를 설치해줍니다.

npm install sequelize sequelize-cli mysql2

sequelize 초기 설정

설치가 완료되면 sequlize init을 실행합니다.
(저는 글로벌 설치를 사용해서 명령어를 바로 사용했습니다. local에서 사용하려면 npx sequelize-cli init을 사용하시면 될거 같습니다.)

실행을 완료하면 다음과 같은 2개의 파일과 4개의 폴더가 생성됩니다.

  • config/cofing.json
    디비에 연결될때 사용되는 설정 정보들
    환경변수로 사용하려면 js파일로 바꾸어야 한다.
  • models/index.js
    만든 모델들을 한번에 불러올 수 있는 index파일이 생성된다.
  • migrations/
    DB에 대한 정보를 바꾸는 경우나 테이블을 생성하고 없애는 상황에서 사용합니다.
  • seeders/
    서버를 실행하거나 콘솔 명령어를 실행했을 때 sequelize를 통해 DB에 데이터를 생성할 때 사용됩니다.

DB 스키마 생성하기

sequelize db:create

명령어를 실행하면 config에 있는 DB 스키마의 이름으로 생성된다.

DB Table 만들기 - migration

sequelize db:migrate

migrations 폴더 안에 이름에 create가 포함된 js파일이 있으면 그것에 맞추어 테이블을 생성해준다.
history테이블이 user테이블의 user_no를 외래키로 가지는 테이블을 구성하려고 한다. 그래서 user 테이블을 먼저 만들기 위해 이름에 1을 붙여줬다.

// 1.create.user.js
"use strict";
module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable(
            "users",
            {
                no: {
                    type: Sequelize.INTEGER,
                    allowNull: false,
                    primaryKey: true,
                    autoIncrement: true,
                },
                id: {
                    type: Sequelize.STRING,
                    allowNull: false,
                },
                password: {
                    type: Sequelize.STRING,
                    allowNull: false,
                },
                username: {
                    type: Sequelize.STRING,
                    allowNull: false,
                },
                deleted: {
                    type: Sequelize.BOOLEAN,
                    allowNull: false,
                    defaultValue: false,
                },
                createdAt: {
                    type: Sequelize.DATE,
                    defaultValue: Sequelize.fn('NOW'),
                },
                updatedAt: {
                    type: Sequelize.DATE,
                    defaultValue: Sequelize.fn('NOW'),
                },
            },
            {
                timestamps: true,
                initialAutoIncrement: 0
            }
        );
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable("users");
    },
};
// 2.create.history.js
"use strict";
module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface
            .createTable(
                "history",
                {
                    id: {
                        type: Sequelize.INTEGER,
                        allowNull: false,
                        primaryKey: true,
                        autoIncrement: true,
                    },
                    input: {
                        type: Sequelize.STRING,
                        allowNull: false,
                    },
                    output: {
                        type: Sequelize.STRING,
                        allowNull: false,
                    },
                    deleted: {
                        type: Sequelize.BOOLEAN,
                        allowNull: false,
                        defaultValue: false,
                    },
                    createdAt: {
                        type: Sequelize.DATE,
                        defaultValue: Sequelize.fn("NOW"),
                    },
                    updatedAt: {
                        type: Sequelize.DATE,
                        defaultValue: Sequelize.fn("NOW"),
                    },
                },
                {
                    timestamps: true,
                }
            )
            .then(async () => {
                await queryInterface.addColumn("history", "user_no", {
                    type: Sequelize.INTEGER,
                });
                await queryInterface.addConstraint("history", {
                    fields: ["user_no"],
                    type: "foreign key",
                    name: "users_history_no_fk",
                    references: {
                        table: "users",
                        field: "no"
                    },
                    onDelete: "cascade",
                    onUpdate: "cascade",
                });
            });
    },
    down: async (queryInterface, Sequelize) => {
        await queryInterface.dropTable("history");
    },
};

외래키 설정하기

외래키를 설정해주기 위해서는 모든 테이블이 완성된 후에 queryInterface를 사용하여 외래키로 사용할 column을 만들어주고 constraint을 추가하여 만들어줘야한다.
그 부분이 2.history.create.js의 아래쪽에 있는 .then()부분에 작성되어있다.

// 2.history.create.js의 아래부분
// ...
.then(async () => {
                await queryInterface.addColumn("history", "user_no", {
                    type: Sequelize.INTEGER,
                });
                await queryInterface.addConstraint("history", {
                    fields: ["user_no"],
                    type: "foreign key",
                    name: "users_history_no_fk",
                    references: {
                        table: "users",
                        field: "no"
                    },
                    onDelete: "cascade",
                    onUpdate: "cascade",
                });
            });
 // ...

.then()은 알고있듯이 비동기를 위한 js의 promise의 실행이 된 후에 호출되는 함수이다.
테이블이 완성된 후에 queryInterfaceuser_no라는 column을 추가한다.
그 이후 addConstraint를 호출하여 history 테이블에 있는 user_nousers_history_no_fk라는 이름의 users테이블의 no값을 부모로 하는 foreign key를 생성한다.

Model 만들기

models 폴더 안에 원하는 이름의 js파일을 생성하면 된다.

module.exports = (sequelize, DataTypes) => {
    const user = sequelize.define(
        "user",
        {
            no: {
                type: DataTypes.INTEGER,
                allowNull: false,
                primaryKey: true,
                autoIncrement: true,
            },
            id: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            password: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            username: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            deleted: {
                type: DataTypes.BOOLEAN,
                allowNull: false,
                defaultValue: false,
            },
        },
        {
            sequelize,
            tableName: "users",
            timestamps: true,
        }
    );
  	user.associate = (models) => {
        user.hasMany(models.history, {
            foreignKey: "user_no",
            onDelete: "cascade",
            allowNull: "false",
        });
    };
    return user;
};
  • DataTypes에 있는 타입들을 가지고 DB에 저장될 타입을 설정한다.
  • allowNull을 줘서 NotNull을 설정 할 수 있다.
  • timestamps을 설정하면 자동으로 created-dateupdated-date를 관리해준다.

associate를 이용하여 관계에 대한 정보를 추가해줘야 모델에 오류없이 사용할 수 있다.
일대다 관계에서는 hasManybelongsTo를 사용하여 연결한다.

module.exports = (sequelize, DataTypes) => {
    const history = sequelize.define(
        "history",
        {
            input: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            output: {
                type: DataTypes.STRING,
                allowNull: false,
            },
            deleted: {
                type: DataTypes.BOOLEAN,
                allowNull: false,
                defaultValue: false,
            },
        },
        {
            sequelize,
            tableName: "history",
            timestamps: true,
        }
    );
    history.associate = (models) => {
        history.belongsTo(models.user, {
            foreignKey: "user_no",
        })
    }
    return history;
};

DB 테이블을 구성할때 주의할 점이 있는데 sequelize는 각 테이블마다 id값을 필수로 요구한다.
그래서 설계를 할때 id 값을 빼놓지 말아야한다.

profile
백엔드 개발자 지망생입니다 :)
post-custom-banner

0개의 댓글