Node.js Sequelize 사용해보기 - 1
2019-09-24 16:42:23

Express에서 Sequelize ORM 사용하여 MySQL CRUD 해보기

작성 당시 sequelize 버전은 5.19.1

설치

1
yarn add sequelize, mysql2

sequelize는 다른 rdb도 지원을 한다. mysql2 대신 다른 rdb 모듈 설치 가능 하다.

설정

init

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
// TODO: sequelize init

const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');

const db = {};

const sequelize = new Sequelize('mysql://root@localhost/test'); // NOTE: mysql connect url

fs.readdirSync(__dirname).filter((file) => (file.indexOf('.') !== 0) && (file !== 'index.js')).forEach((file) => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});

Object.keys(db).forEach((modelName) => {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.Op = Sequelize.Op; // NOTE: v5부턴 이걸 해줘야 조건절 equal같은거 쓸수 잇음.

module.exports = db;

sequelize를 사용하기 위한 이니셜라이즈라고 알아두면 된다.

테이블 스키마 만들기

테이블 스키마를 정의해야 사용할 수 잇음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = (sequelize, DataTypes) => {
const animes = sequelize.define('animes', { // NOTE: 'animes'는 테이블명
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, // NOTE: primary key
title: DataTypes.STRING,
quarter: DataTypes.STRING,
createAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
},
{
timestamps: false,
});
return animes;
};

자주 쓰는 데이터 타입만 적어두자.

  • DataTypes.INTEGER = 정수형 int
  • DataTypes.STRING = 문자형 varchar(255)
  • DataTypes.TEXT = 문자형 TEXT
  • DataTypes.DATE = 날짜 DATETIME
  • DataTypes.BOOLEAN = tinyint 1/0

연결

앱 실행 시 db에 연결하고 스키마에 정의된 테이블이 업으면 생성을 한다.

아 스키마를 변경한다고 이미 생성된 테이블이 변경되진 않는다.

1
2
3
4
5
6
7
db.sequelize
.sync()
.then(() => {
console.log('DB 연결 성공');
}).catch((e) => {
throw new Error(e);
});

crud

router에 paramter가 오는 값으로 crud를 해본다.

create

1 row를 생성

1
2
3
4
5
6
7
8
// TODO: create
router.post('/create', (req, res) => {
const { title, quarter } = req.body;
db.animes.create({
title,
quarter,
}).then((result) => res.json(result)).catch((e) => res.json(e));
});

실행 결과

여러 개 create

1
2
3
4
5
// TODO: multiple create
router.post('/multiple-create', (req, res) => {
const { data } = req.body; // NOTE: Array Object [{}, {} ... ]
db.animes.bulkCreate(data).then((result) => res.json(result)).catch((e) => res.json(e));
});

실행 결과

read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
router.post('/select', (req, res) => {
const { id } = req.body;
db.animes.findAll({
where: {
id,
// id: { // NOTE: >, = 같은 조건식을 쓰는 방법.
// [db.Op.gt]: id,
// },
},
// limit: 1, // NOTE: 개수 제한
// attributes: ['title'], // NOTE: 특정 컬럼만 읽을 때
// order: ['id', 'desc'], // NOTE: 정렬
}).then((result) => { // NOTE: 결과는 []에
if (!result.length) return res.json({ message: 'NOT FOUND' });
return res.json(result);
}).catch((e) => res.json(e));
});

실행 결과

조건절 정리

  • gt: >
  • eq: ==
  • gte: >=
  • in: Array 안에 포함
  • lt: <
  • lte: <=
  • ne: !=
  • nin: Array 안에 포함하지 않은

update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// TODO: update
router.post('/update', (req, res) => {
const { id, title } = req.body;
db.animes.update(
{
title,
},
{
where: {
id,
},
},
).then(() => res.json({ message: 'update success' })).catch((e) => res.json(e));
});

업데이트 된 내용을 콜백 받진 않는다.

delete

1
2
3
4
5
6
7
8
9
// TODO: delete
router.post('/delete', (req, res) => {
const { id } = req.body;
db.animes.destroy({
where: {
id,
},
}).then(() => res.json({ message: 'delete success' })).catch((e) => res.json(e));
});

업데이트와 마찬가지로 별도로 콜백 받는게 업다.