Sequelize 사용하기

ORM 이란?

**관계형 데이터베이스(RDB)**를 사용할때 데이터베이스의 데이터 조작(CRUD)를 위해서는 SQL 문을 작성해야합니다. SQL 문은 비즈니스 로직을 구성하고 있는 코드와 함께 작성하게 되는데 이는 코드의 가독성을 떨어뜨릴뿐만 아니라, 사용하는 관계형 데이터베이스에 따라 조금씩의 차이가 존재하기 때문에 문제가 발생할 수 있습니다. 이를 해결하기 위해 ORM을 사용합니다.

**ORM(Object Relational Mapping)**은 객체(Object)와 관계(Relation)를 맵핑(Mapping)하여 비즈니스 로직에 집중할 수 있도록 데이터 처리 로직을 추상화시킵니다.

객체와 관계를 매핑한다는 것은 데이터베이스에 저장된 레코드를 객체로 바꿔표현한다는 의미하며, 비즈니스 로직에 집중할 수 있도록 데이터 처리 로직을 추상화한다는 것은 쿼리를 사용하지 않고도 데이터베이스를 사용할 수 있음을 뜻합니다.

ORM을 사용할 경우 특정 DBMS에 종속되지 않으며 생산성, 독립성, 가독성(SQL문이 코드에 들어가지 않기때문) 및 유지보수 측면에서의 장점이 있지만 반대로 RAW query에 비해 퍼포먼스가 떨어지고, query가 복잡해 질수록 오히려 생산성이 저하될 수 있다는 단점도 존재합니다.

ORM

Sequelize 설치하기

**Sequelize**는 Node에서 가장 많이 사용되는 ORM 입니다.

RDS로 PostgresSQL, MySQL, MariaDB, SQLite, MSSQL을 지원하고 transaction, read replication등 다양한 기능을 제공하고 있으며. 또한 Promise를 기본으로 동작하기 때문에 비동기 코드를 보기좋게 작성할 수 있습니다.

실습을 위해 express-generator를 통해 Express 프로젝트를 생성후 sequelizemysql module을 설치합니다. (Express 프로젝트를 생성하는 부분은 생략합니다.)

1
npm install --save sequelize mysql

**Sequelize Command Line Interface(CLI)**를 사용하기 위해서 sequelize-cli module을 설치합니다.

1
npm install -g sequelize-cli

Sequelize CLI 사용하기

sequelize cli를 통해서 **migration(마이그레이션), seeder(시더), model(모델)**의 초기 설정을 손쉽게 할 수 있습니다. 이번 포스팅에서는 model에 관해서 알아보겠습니다.

RDB의 테이블을 model로 정의를 하면 해당 model을 통해 데이터 처리가 가능하게 됩니다.
먼저 생성한 express 프로젝트에 sequelize cli 명령어를 통해 sequelize 설정 파일을 생성 후 model을 정의해 보겠습니다.

1
2
sequelize init:config --config config/sequelize.json
sequelize init:models

sequelize cli의 sequelize init:config라는 명령어로 sequelize관련 config 파일을 자동으로 생성할 수 있습니다. 아무런 옵션을 주지 않는다면 config/config.json 파일이 생성됩니다.

sequelize init:models 명령어를 통해서는 models 정의에 관련된 기본 구조를 생성할 수 있습니다.

위 2개의 명령어를 실행하면 다음과 같은 폴더와 파일이 생성됩니다.

1
2
3
4
├── config/
└── sequelize.json
├── models/
└── index.js

Sequelize config 설정하기

sequelize cli를 통해 생성한 config/sequelize.json파일에 데이터베이스에 관련된 설정 값을 입력합니다.

NODE_ENV 에 따라 각기 다른 값을 사용하기 때문에 상황에 맞게 설정할 수 있습니다. NODE_ENV에 대해 잘 알지 못한다면 이곳을 참고하세요.

데이터베이스를 사용한 프로젝트 경험이 있다면 대부분의 config 값은 입력할 수 있습니다. config 값중 dialect에는 사용하는 RDB 이름을 입력해야 합니다. diaect에 사용 가능한 값은 sequelize docs를 참고하세요. 현재 사용 가능한 RDB 로는 ‘mysql’, ‘sqlite’, ‘postgress’, ‘mariadb’가 있습니다.

추가적으로 커넥션 풀과 로깅 기능을 사용한다면 해당 값을 추가합니다. 추가적으로 필요한 옵션은 docs를 참고하세요.

1
2
3
4
5
6
"pool": {
"max": 20,
"min": 0,
"idle": 5000
},
"logging": true

# Model 정의하기

Model을 생성하기 전 sequelize cli를 통해 생성한 models/index.js파일을 살펴보겠습니다. index.js 의 역할은 config/sequelize.json의 설정값을 읽어 sequelize를 생성한 후 models 폴더 아래에 정의한 model 관련 js 파일을 모두 로딩하여 db 객체에 Model을 정의한 후 반환합니다.

sequelize config 관련 파일을 sequelize.json으로 생성하였다면 config 파일을 불러오는 require 부분의 경로를 수정해주어야 합니다.

이제 models 폴더 아래에 간단한 모델을 정의해 보겠습니다. **user.js**를 생성 후 다음의 코드를 입력합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
module.exports = function (sequelize, DataTypes) {
const user = sequelize.define('User', {
userID: { field: 'user_id', type: DataTypes.STRING(50), unique: true, allowNull: false },
password: { field: 'password', type: DataTypes.STRING(30), allowNull: false },
}, {
// don't use camelcase for automatically added attributes but underscore style
// so updatedAt will be updated_at
underscored: true,

// disable the modification of tablenames; By default, sequelize will automatically
// transform all passed model names (first parameter of define) into plural.
// if you don't want that, set the following
freezeTableName: true,

// define the table's name
tableName: 'user'
});

return user;
};

/*
Sequelize 참고
DataTypes => http://docs.sequelizejs.com/en/v3/api/datatypes/
Associations => http://docs.sequelizejs.com/en/v3/api/associations/
Model Function => http://docs.sequelizejs.com/en/v3/api/model/
*/

Model을 생성하며 사용된 옵션은 주석과 docs를 참고합니다. 이제 모델에 대한 정의가 끝났습니다. 데이터베이스에 user라는 테이블은 User라는 Object로 매핑되었고 user_id, password라는 칼럼은 User Object의 속성으로 매핑되었습니다.

Sequelize Sync 사용하기

Sequeliz에서는 **입력(INSERT), 수정(UPDATE), 조회(SELECT), 삭제(DELETE)**의 **데이터 조작(DML: Data Manipulation Language)**뿐만 아니라 데이터베이스의 스키마 객체를 생성(CREATE), 변경(ALERT), 제거(DROP) 할 수 있는 **데이터 정의(DDL: Data Definition Language)**도 지원합니다.
따라서 이미 만들어진 데이터베이스 테이블에 모델을 매핑할 수 있을 뿐만 아니라, 정의한 모델을 바탕으로 테이블을 생성할 수도 있습니다.(동기화)

해당 기능을 사용하기 위해서는 Sequelize의 sync 메서드를 사용합니다. **app.js**에 다음의 코드를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
// connect To DB
const models = require('./models');
models.sequelize.sync()
.then(() => {
console.log('✓ DB connection success.');
console.log(' Press CTRL-C to stop\n');
})
.catch(err => {
console.error(err);
console.log('✗ DB connection error. Please make sure DB is running.';
process.exit();
});

sync 메서드를 호출하여 실패했을 경우에는 에러 메시지를 출력 후 프로세스를 종료합니다.

sync 메서드는 모델에서 정의한 이름의 테이블이 존재하지 않을 경우에만 동작합니다. 이미 테이블이 존재할 경우에는 models.sequelize.sync({force: true}) 과 같이 force 옵션을 주어 강제적으로 테이블을 제거 후 다시 생성이 가능하지만 매우 위험한 옵션이므로 주의를 기울여 사용해야 합니다.

Sequelize 예제 (SELECT)

이제 Sequelize를 사용하여 SELECT를 사용해보겠습니다. 유저 리스트를 가져오는 query는 다음과 같습니다.

1
2
3
4
5
6
7
models.User.findAll()
.then(results) {
res.json(results);
})
.catch(err => {
console.error(err);
});

User 테이블에 있는 모든 row를 가져오는 query입니다. Sequelize는 결과를 Promise로 리턴하기 때문에 findAll 메서드 역시 Promise를 리턴합니다. 따라서 query의 결과는 then에서 받고, catch문에서 상황에 맞게 error 처리(handling)를 하면됩니다.

findAll의 더 자세한 사용법은 Sequelize-model-findAll 설명을 참고합니다.

Sequelize 예제 (INSERT)

Sequelize를 사용하여 INSERT를 하는 방법은 다음과 같습니다.

1
2
3
4
5
6
7
models.User.create({userID: '유저ID', password: '유저PW'})
.then(result => {
res.json(result);
})
.catch(err => {
console.error(err);
});

create 메서드의 매개변수에 model에서 매핑한 내용을 토대로 데이터를 넣으면 query를 실행 후 insert된 row정보가 반환됩니다.

create의 더 자세한 사용법은 Sequelize-model-create 설명을 참고합니다.

Sequelize 예제 (UPDATE)

User 테이블의 데이터를 수정할때는 다음과 같이 사용합니다.

1
2
3
4
5
6
7
models.User.update({password: '새로운 유저PW'}, {where: {userID: '유저ID'}})
.then(result => {
res.json(result);
})
.catch(err => {
console.error(err);
});

update 메서드의 매개변수에는 update할 데이터를 입력합니다.

update 더 자세한 사용법은 Sequelize-model-update 설명을 참고합니다.

Sequelize 예제 (DELETE)

User 테이블의 데이터를 삭제할때는 다음과 같이 사용합니다.

1
2
3
4
5
6
7
models.User.destroy({where: {userID: '유저ID'}})
.then(result => {
res.json({});
})
.catch(err => {
console.error(err);
});

destroy 메서드의 매개변수에는 where 조건을 입력합니다.(where 조건을 입력하지 않을 경우 테이블의 모든 row가 삭제되기 때문에 주의해야 합니다.)

destroy 더 자세한 사용법은 Sequelize-model-update 설명을 참고합니다.