Sequelize ORM

Jiyoung·2021년 2월 27일
0

ORM이란?

이미지 출처: codestates urclass

ORMObject Relational Mapping의 약자로, 자바스크립트의 객체와 관계형 데이터베이스 간(객체와 모델 간) 통역을 담당하는 역할을 한다. 객체 지향 프로그래밍(OOP)에서와 관계형 데이터베이스에서의 접근 방식은 조금 다른데, 이를 프로그래밍 언어의 관점에서 맞출 수 있도록 도와주는 것이 바로 ORM이다. ORM을 통해 자바스크립트 코드를 자동으로 SQL문으로 생성할 수 있기 때문에 SQL문을 직접 작성하지 않아도 데이터베이스에 접근할 수 있다는 장점이 있다.

Sequelize

Sequelize는 Promise기반의 Node.js용 ORM으로, MySQL, MariaDB, Microsoft SQL Server 등 다양한 RDBMS를 지원한다. SQL문을 각 RDBMS에서 조금씩 다르게 출력하는 경우가 있는데 이를 Sequelize가 다 맞춰줘서(호환성↑) 다양한 RDBMS를 사용할 수 있도록 해준다.

// Sequelize ORM을 사용한 예시 코드
var Sequelize = require('sequelize');
var db = new Sequelize('chatter', 'root', '');

var User = db.define('User', {
  username: Sequelize.STRING
});

var Message = db.define('Message', {
  userid: Sequelize.INTEGER,
  text: Sequelize.STRING,
  roomname: Sequelize.STRING
}); 
// db.define은 스키마 작성 부분. 
// STRING, INTEGER 등은 RDBMS 간 다양한 field타입의 호환성을 유지시켜주기 위해 Sequelize에서 만든 데이터 타입.
// User, Message 등을 Class처럼 사용할 수 있게 해줌.
// id, CreatedAt, UpdatedAt은 자동으로 생성해줌.

User.sync()
  .then(function() {
    return User.create({username: 'Jean Valjean'});
  }) // 데이터 생성, 해당 값은 객체로 입력. INSERT INTO ~~ VALUES구문과 동일.
  .then(function() {
    return User.findAll({ where: {username: 'Jean Valjean'} });
  }) // 데이터 조회. SELECT * FROM ~~ WHERE구문과 동일.
  .then(function(users) {
    users.forEach(function(user) {
      console.log(user.username + ' exists');
    });
    db.close();
  })
  .catch(function(err) {
    console.error(err);
    db.close();
  });

ORM 설정

먼저 Sequelize CLI 를 설치한다. sequelize-cli는 마이그레이션을 할 수 있도록 돕는 툴로, CLI에서 모델을 생성해주거나, 스키마 적용을 할 수 있도록 해준다.

npm install --save-dev sequelize-cli

cli를 통해 ORM을 잘 사용할 수 있도록 bootstraping(프로젝트 초기 단계를 자동으로 설정할 수 있도록 도와주는 일)을 해줘야 한다.

npx sequelize-cli init

성공적으로 bootstraping이 끝나면 다음 파일 및 폴더들이 생성된다.

config/config.json // DB 연결 정보 등을 저장
models/ // DB 모델 정의를 저장
migrations/ //마이그레이션에 필요한 데이터가 자동으로 저장됨
seeders/ //테스트에 필요한 데이터를 정의

다음으로는 아래와 같이 생성된 config/config.json 파일을 이용해서 DB(MySQL)접속 설정을 해야한다. 여기서 눈여겨 볼 특징은 development, test, production 등 개발 환경에 따라 서로 다른 DB를 사용할 수 있다는 점이다.

{
  "development": { // 개발 환경
    "username": "root", // DB 사용자 이름
    "password": "your_password", // DB 비밀번호
    "database": "database_development", // 사용할 DB
    "host": "127.0.0.1", // DB 주소
    "dialect": "mysql" // DBMS
  },
  "test": { // 테스트 환경
    "username": "root",
    "password": "your_password",
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": { // 운용 환경
    "username": "root",
    "password": "your_password",
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

development, test, production와 같은 객체의 Key들은 'model/index.js'파일에서 환경 변수(process.env.NODE_ENV)를 일치시켜주는 데 사용된다. 환경 변수가 따로 정의되지 않을 경우 기본값은 development이다.

const env = process.env.NODE_ENV || 'development';

데이터베이스가 아직 생성되지 않았다면 npx sequelize db:create 명령어를 실행해주면 된다.

Model 생성

모델(Model)은 엔티티를 객체로 표현한 형태로, 데이터 구조를 기술하고, 데이터에 수행할 수 있는 명령의 모음을 의미한다. cli를 통해 모델을 생성 할 수 있다. name에는 모델의 이름을, attributes에는 모델에 생성하고자 하는 필드를 입력해주면 된다. id, createdAt, updatedAt 필드는 자동으로 생성된다. 모델을 잘못 만든 경우, 생성된 파일을 직접 수정하거나 삭제 후 명령을 다시 실행할 수 있다.

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

위 명령어를 실행하면 models 폴더에 user라는 모델 파일이 생성되며, migrations 폴더에 'XXXXXXXXXXXXXX-create-user.js'형식의 migration 파일이 생성된다.

Migration

마이그레이션(Migration)은 스키마 변경에 따른 데이터 이주를 의미한다. 따라서 스키마 변경이 있을 때마다 마이그레이션을 실행해줘야 한다.

모델을 생성하는 단계까지는 아직 데이터베이스에 데이터가 삽입되지 않은 상태이다. 즉 모델 파일과 마이그레이션 파일만 생성되었을 뿐이다. 마이그레이션을 위해 아래의 명령을 실행하면 마이그레이션 파일의 스키마대로 데이터베이스에 테이블이 생성된다. 테이블 이름을 설정해주지 않은 경우 Sequelize에서 모델 이름의 복수형으로 테이블 이름을 자동으로 생성해준다. 모델 이름이 User일 경우, 테이블 이름은 Users가 된다.

npx sequelize-cli db:migrate

가장 최근에 실행한 마이그레이션으로 되돌리고 싶을 경우는 아래의 명령어를 실행하면 된다.

npx sequelize-cli db:migrate:undo

마이그레이션 파일은 아래와 같은 형식으로 작성되어 있다.

module.exports = {
  up: (queryInterface, Sequelize) => {
    // logic for transforming into the new state
  },
  down: (queryInterface, Sequelize) => {
    // logic for reverting the changes
  }
}

여기서 up에는 npx sequelize-cli db:migrate명령을 실행했을 때, down에는 npx sequelize-cli db:migrate:undo명령을 실행했을 때 원하는 값이 나오도록 코드를 작성해주면 된다.

Migration Skeleton

순수하게 필드 수정만을 담당하는 마이그레이션 파일을 직접 생성할 수 있다. 아래 명령어를 실행하면 migration 폴더에 'xxx-migration-skeleton.js'형식의 파일이 생성된다.

npx sequelize-cli migration:generate --name migration-skeleton

전달된 queryInterface 객체로 데이터베이스를 수정할 수 있으며, up과 down 함수는 반드시 Promise를 반환해야 한다.

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Person', {
      name: Sequelize.DataTypes.STRING,
      isBetaMember: {
        type: Sequelize.DataTypes.BOOLEAN,
        defaultValue: false,
        allowNull: false
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('Person');
  }
};

Association

Association은 '연관'이라는 의미대로 모델 간 관계를 정의해주는 것을 말한다. Sequelize에는 HasOne, BelongsTo, HasMany, BelongsToMany 등 4가지 유형의 Association이 있다(참고링크).

1:1 관계(HasOne, BelongsTo)

Foo와 Bar라는 두 모델 간 1:1관계를 설정하고자 한다면, 결과적으로는 아래처럼 실행이 되어야 한다.

Foo.hasOne(Bar);
Bar.belongsTo(Foo);

1:N 관계(HasMany, BelongsTo)

Team과 Player라는 두 모델 간 1:N관계를 설정하고자 한다면, 결과적으로는 아래처럼 실행이 되어야 한다.

Team.hasMany(Player);
Player.belongsTo(Team);

N:N 관계(BelongsToMany)

N:N관계는 다음과 같다.

const Movie = sequelize.define('Movie', { name: DataTypes.STRING });
const Actor = sequelize.define('Actor', { name: DataTypes.STRING });
Movie.belongsToMany(Actor, { through: 'ActorMovies' });
Actor.belongsToMany(Movie, { through: 'ActorMovies' });
profile
경계를 넘는 삶

0개의 댓글