NodeJS 에서 Sequelize 사용하기

Sequelize for NodeJS

2019-02-08

Sequelize

Sequelize는 Node에서 데이터베이스 접속시 편리하게 작업할 수 있도록 도와주는 라이브러리입니다. ORM(Object-relational Mapping)으로 자바스크립트 객체와 데이터베이스 릴레이션을 맵핑해 주고 자바스크립트 구문을 알아서 SQL로 바꾸어 질의하기 때문에 SQL 문법을 몰라도 데이터베이스를 다룰 수 있게 도와줍니다. 더욱이 MySql, MariaDB, PostgreSQL, SQLite, MSSQL등 다른 데이터베이스도 같이 쓸 수 있기 때문에 유용하게 활용할 수 있습니다.

Sequelize 설치

Sequelizemysql을 설치하고 sequelize 커맨드를 사용하기위해 sequelize-cli 를 전역으로 설치합니다. 설치 완료후 sequelize init 명령어를 실행해 줍니다.

1
2
3
npm i sequelize mysql2
npm i -g sequelize-cli
sequelize init

Model 생성

sequelize init 명령으로 생성된 models/ 폴더에 sequelize.define 메소드를 사용하여 mysql table과 대응되는 sequelize model을 추가해 줍니다.

sequelize는 기본적으로 model이름은 단수로 생성하며, 단수 모델명의 복수형 이름을 테이블 명으로 사용합니다. 그리고 id를 기본키로 연결하므로 id컬럼을 추가할 필요는 없습니다.

1
sequelize.define('modelName', column, option);

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 = ({sequelize, DataTypes = Sequelize}) => {
return sequelize.define(
// model name
'user',
// column
{
name: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defalutValue: sequelize.literal('now()'),
}
},
// options
{
timestamps: false
}
)
};

dataType

sequelize.define를 사용하여 column 선언시 속성의 dataType은 SQL문 dataType과는 조금 다른 이름으로 선언합니다.

  • VARCHAR: STRING
  • INT: INTEGER
  • UNSIGNED 옵션이 적용된 INT: INTEGER.UNSIGNED
  • ZEROFILL옵션: INTEGER.UNSIGNED.ZEROFILL
  • TINYINT: BOOLEAN
  • DATETIME: DATE
  • NOT NULL: allowNull
  • UNIQUE: UNIQUE
  • 기본값: defaultValue

options

  • timestamps: true 일 경우 createdAt, updatedAt 컬럼을 자동으로 추가하고 row가 생성, 수정될 때 시간이 자동으로 입력됩니다.
  • paranoid: timestamps 가 true 경우에만 사용가능합니다. deletedAt 이라는 컬럼이 추가되며 row 삭제하는 sequelize 명령 내릴 경우 deletedAt에 제거 날짜를 입력합니다.
  • underscored: sequelize가 자동으로 생성해주는 컬럼명을 스네이크 형식으로 변경합니다. createdAt, updatedAt, deletedAt 컬럼을 각각 created_at, updated_at, deleted_at으로 변경해 줍니다.
  • tableName: sequelize는 자동으로 define 메소드 첫번째 인자(모델명)를 복수형으로 만들어 테이블명으로 사용합니다. 테이블 명을 다른 것으로 지정하고 싶을 때 해당 옵션을 사용합니다.

Model 간 관계 선언

아래 메소드들을 사용하여 table에 해당하는 model간 관계를 맺어줍니다.

doc associations

  • HasOne: One-to-one association
  • HasMany: One-to-many association
  • BelongsTo: One-to-one association
  • BelongsToMany: Many-to-many association with a join table.

1:1

1:1 경우 hasOne, belongTo가 반대여도 상관없습니다.

1
2
db.User.hasOne(db.Info, { foreginKey:"user_id", sourceKey:"id"});
db.Info.belongTo(db.User, { foreginKey:"user_id", tarketKey:"id"});

1:N

foreginKey 를 사용하여 관계를 맺어줄 경우 hasMany는 sourceKey, belongTo는 targetKey를 사용합니다.

1
2
User.hasMany(Comment, { foreginKey:"commenter", sourceKey: "id"}); 
Comment.belongTo(User, { foreginKey:"commenter", targetKey: "id"}); // User 모델의 id를 Comment 모델의 commenter 컬럼에 넣습니다.

N:M

새로운 릴레이션으로 사용될 이름을 through 속성의 값으로 넣어줍니다.

1
2
Post.belongToMany(HashTag, { through:"PostHashTag"});
HashTag.belongToMany(Post, { through:"PostHashTag"});

설정 및 데이터베이스 연동

config/config.json

데이터베이스 연동을 위한 정보를 담을 config 파일을 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
{
"development": {
"username": "root",
"password": "password",
"database": "nodejs",
"host": "127.0.0.1",
"dialect": "mysql",
"operatorsAliases": false // 보안에 취약한 연산자를 사용할지 여부
},
"production": {...},
"test": {...}
}

models/index.js

sequelize init 명령으로 생성된 models/index.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
const path = require('path');
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require('../confing/config')[env];
const db = {};
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

// model 정의
db.User = require('./user')(db); // user model
db.Post = require('./post')(db); // post model

// model간 관계 선언
db.User.hasMany(db.Post);
db.Post.belongsTo(db.User);

module.exports = db;

model/index.js 에서 config.json 파일을 불러와 sequelize 인스턴스를 생성하고 정의된 model간 관계를 선언합니다.

app.js

sequelize.sync() 메소드를 호출하여 데이터베이스완 연동합니다.

1
2
3
const sequelize = require('./models').sequelize;
const app = express();
sequelize.sync();

CRUD

findAll, destroy, update 같은 메소드들을 사용하여 database에 질의할 수 있습니다. 좀 더 자세한 사용은 아래 링크를 참조해 주세요.
doc querying

조회 Option 객체

  • attribute
  • where
  • order
  • limit : // find 메소드랑 동일
  • offset

Sequelize Op 연산자

  • Op.gt : 초과
  • Op.gte : 이상
  • Op.lt : 미만
  • Op.lte : 이하
  • Op.ne: 같지않음
  • Op.or: 또는
  • Op.in: 배열 요소중 하나
  • Op.notln: 배열 요소와 모두 다름

Controller 사용 예

routes/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express');
const User = require('../models').User;
const router = express.Router();

router.get('/', async(req, res, next) => {
try{
const users = await User.findAll();
res.render('viewTemplate', {users});
} catch (error) {
next(error);
}
});

module.exports = router;

READ

1
const { User, Sequelize: { Op } } = require('../models');
1
2
3
4
5
// SELECT * FROM db.users LIMIT 1;
User.find({})
User.findAll({
limit: 1
});
1
2
// SELECT * FROM db.users;
User.findAll({});
1
2
3
4
// SELECT name, married FROM db.users;
User.findAll({
attribute: ['name','married'],
});
1
2
3
4
5
6
7
8
9
// SELECT name, married FROM db.users WHERE married=1 AND age > 30 ORDER BY age DESC;
User.findAll({
attribute: ['name','married'],
where: {
married: 1,
age:{ [Op.gt]: 30 },
},
order: [['age','DESC']]
});
1
2
3
4
5
6
7
8
// SELECT name, married FROM db.users WHERE married=0 OR age > 30 ORDER BY age DESC;
User.findAll({
attribute: ['name','married'],
where: {
[Op.or]: [{ married: 0 }, { age: { [Op.gt]: 30 } }
},
order: [['age','DESC']]
});

N:M 관계에서 테이블 조회(get, set, add + 모델명의 복수형 메소드 사용 가능)

1
2
3
4
async(req, res, next) => {
const tag = await HashTag.find({ where: { title: "dev" } });
const post = await tag.getPosts(); // get + 모델명의 복수형
};

UPDATE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// UPDATE db.users SET column="바꿀내용" WHERE id=2;
User.update({
column: "바꿀내용"
},{
where: { id: 2 }
});
````

### DELETE
```javascript
// DELETE FROM db.users WHERE id=2;
User.destroy({
where: { id: 2 }
});

Sequelize는 ORM으로써 편리하게 사용할 수 있지만 모델링 및 SQL 문에 대한 이해를 가지고 사용하는 것이 좋을 것 같습니다. 좀 더 자세한 사용법은 Sequelize API 문서를 참고해 주세요.