티스토리 뷰
- 이번 프로젝트에서 Sequelize를 사용했습니다.
mysql vs mysql2 vs promise-mysql vs Sequelize
mysql
- 세계에서 가장 많이 사용되는 오픈 소스 데이터베이스입니다.
- 매우 빠른 다중 스레드, 다중 사용자 및 강력한 SQL 데이터베이스 서버를 제공합니다.
- MySQL 서버는 mission critical하고 로드가 많은 프로덕션 시스템과 대량 배포 소프트웨어에 내장하기 위한 것입니다.
- mission critical : 업무 수행을 위하여 가장 중요한 요소(국방, 의료, 금융 등)에서 작은 실수만으로도 치명적인 결과를 초래하는 분야를 뜻합니다.
Sequelize?
- Node.js에 사용하기 쉬운 promise 기반 ORM입니다.
- 견고한 transaction 지원, relations, read replication 등을 제공합니다
ORM?
- ORM이란 Object Relational Mapper의 약자로, 객체와 관계와의 설정이라 할 수 있습니다.
- 자바스크립트 객체와 데이터베이스의 릴레이션을 매핑해준다고 생각하면 됩니다.
왜 why? Sequelize?
- Sequelize를 사용한 이유는 promise 기반 ORM이기 때문입니다.
- 자바스크립트 구문을 알아서 SQL로 바꿔주기 때문입니다.
- SQL 언어를 직접 사용하지 않아도 자바스크립트만으로 MySQL을 조작할 수 있습니다.
- 물론 MySQL을 모르는 채로 사용하는 것보다는 알고 사용하는 것이 좋습니다.
sequeilze 사용하기
1. 필요한 라이브러리
- sequelize와 mysql2 패키지를 설치해야 합니다.
- 그 뒤 sequelize init을 통해 필요한 폴더들을 설치해줍니다.
2. config
{
"development": {
"username": "TokDDak RDS 아이디",
"password": "TokDDak RDS 비밀번호",
"database": "tokddak",
"host": "TokDDak RDS 주소",
"dialect": "mysql"
},
"test": {
"username": "local(Workbench) ID",
"password": "local(Workbench) 비밀번호",
"database": "tokddak",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
- sequelize의 장점으로 development와 test, production을 나누어서 Database 테스트를 할 수 있습니다.
- 프로젝트에서 test 데이터베이스는 local workbench에서 진행하였고, 실제 애플리케이션 데이터베이스는 RDS에서 진행하였습니다.
3. models/index.js
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};
const sequelize = new Sequelize(
config.database, config.username, config.password, config
);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.City = require('./cityModel')(sequelize, Sequelize);
db.Activity = require('./activityModel')(sequelize, Sequelize);
db.Food = require('./foodModel')(sequelize, Sequelize);
db.Shopping = require('./shoppingModel')(sequelize, Sequelize);
db.Snack = require('./snackModel')(sequelize, Sequelize);
db.Hotel = require('./hotelModel')(sequelize, Sequelize);
db.Transport = require('./transportModel')(sequelize, Sequelize);
db.Trip = require('./tripModel')(sequelize, Sequelize);
db.TripActivity = require('./tripActivityModel')(sequelize, Sequelize);
db.TripFood = require('./tripFoodModel')(sequelize, Sequelize);
db.TripSnack = require('./tripSnackModel')(sequelize, Sequelize);
db.TripHotel = require('./tripHotelModel')(sequelize, Sequelize);
db.Median = require('./medianModel')(sequelize,Sequelize);
db.Schedule = require('./scheduleModel')(sequelize, Sequelize);
db.User = require('./userModel')(sequelize, Sequelize);
db.Timeline = require('./timelineModel')(sequelize, Sequelize);
/** 1:N T : Timeline */
db.Trip.hasMany(db.Timeline);
db.Timeline.belongsTo(db.Trip);
/** 1:N T : Schedule */
db.Trip.hasMany(db.Schedule);
db.Schedule.belongsTo(db.Trip);
/** 1:N City : Activity */
db.City.hasMany(db.Activity);
db.Activity.belongsTo(db.City);
/** 1:N City : Food */
db.City.hasMany(db.Food);
db.Food.belongsTo(db.City);
/** 1:N City : Shopping */
db.City.hasMany(db.Shopping);
db.Shopping.belongsTo(db.City);
/** 1:N City : Snack */
db.City.hasMany(db.Snack);
db.Snack.belongsTo(db.City);
/** 1:N City : Hotel */
db.City.hasMany(db.Hotel);
db.Hotel.belongsTo(db.City);
/** 1:N City : Transport */
db.City.hasMany(db.Transport);
db.Transport.belongsTo(db.City);
/** 1:N Trip : TripActivity */
db.Trip.hasMany(db.TripActivity, {
onDelete: 'cascade'
});
db.TripActivity.belongsTo(db.Trip);
/** 1:N Trip : TripHotel */
db.Trip.hasMany(db.TripHotel, {
onDelete: 'cascade'
});
db.TripHotel.belongsTo(db.Trip);
/** 1:N Trip : TripFood */
db.Trip.hasMany(db.TripFood, {
onDelete: 'cascade'
});
db.TripFood.belongsTo(db.Trip);
/** 1:N Trip : TripSnack */
db.Trip.hasMany(db.TripSnack, {
onDelete: 'cascade'
});
db.TripSnack.belongsTo(db.Trip);
// Shopping이랑 Transport는 사용자가 금액을 입력하므로 따로 1:N 테이블을 만들지 않는다.
/** 1:N Trip : Schedule */
db.Trip.hasMany(db.Schedule, {
onDelete: 'cascade'
});
db.Schedule.belongsTo(db.Trip);
/** 1:N User : Trip */
db.User.hasMany(db.Trip);
db.Trip.belongsTo(db.User);
module.exports = db;
- models/index.js에서 데이터베이스 테이블 및 테이블 간 관계를 설정할 수 있습니다.
- 프로젝트에서 사용한 테이블 수는 16개이고, 관계는 1:N만을 사용했습니다.
- 1:1, N:M, 한 테이블에서의 N:M은 다음 게시물에 블로깅하겠습니다!
4. models 사용
- Sequelize에서 주로 사용되는 문법은 다음과 같습니다.
- findAll
- findOne
- create
- update
- destory
- 하나하나 차근차근 살펴보겠습니다.
- 다음은 실제 프로젝트에서 사용했던 코드입니다.
const rm = require('../module/util/responseMessage');
const utils = require('../module/util/utils');
const sc = require('../module/util/statusCode');
const fn = require('sequelize').fn; // orderby를 위해 사용했던 sequelize 문법
const col = require('sequelize').col; // table col을 가져오기 위해 사용했던 sequelize
const {Trip} = require('../models');
- 특정 테이블의 CRUD를 사용하기 위해서는 models/index에서 require해옵니다.
- Trip 테이블을 사용한다고 해서 require('../models/Trip')를 하면 오류가 발생하게 됩니다.
4-1. findAll
totalDayRead : ({
TripId
}) => {
return new Promise(async (resolve, reject) => {
const trip = await Trip.findOne({
where: {
id: TripId,
},
attributes: ['totalDay']
});
console.log(trip);
console.log(typeof trip);
if (!trip) {
resolve({
code: sc.INTERNAL_SERVER_ERROR,
json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.TRIP_READ_FAIL)
});
return;
}
if (trip.length == 0) {
resolve({
code: sc.NO_CONTENT,
json: utils.successFalse(sc.NO_CONTENT, rm.TRIP_EMPTY)
});
return;
}
resolve({
code: sc.SUCCESS,
json: utils.successTrue(sc.SUCCESS, "여행 일수를 조회합니다.", trip)
});
});
},
- Trip.findAll에서 where절을 설정하여 모든 정보를 가져오게 됩니다.
- attributes 옵션을 추가하여 가져오고 싶은 속성정보만 가져올 수 있습니다.
- findOne은 row 정보 하나만 가져오고 findAll과 문법은 일치합니다.
4-2. create
create: ({
title,
momentStart,
momentEnd,
activityBudget,
hotelBudget,
foodBudget,
shoppingBudget,
snackBudget,
transportBudget,
totalDay,
CityId,
UserId
}) => {
return new Promise(async (resolve, reject) => {
const obj = new Object();
let trip;
try {
trip = await Trip.create({
title: title,
start: momentStart,
end: momentEnd,
city : city.dataValues.name,
country: city.dataValues.country,
activityBudget: activityBudget,
hotelBudget: hotelBudget,
foodBudget: foodBudget,
shoppingBudget: shoppingBudget,
snackBudget: snackBudget,
transportBudget: transportBudget,
totalDay: totalDay,
UserId: UserId
});
} catch (error) {
reject({
code: sc.INTERNAL_SERVER_ERROR,
json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.TRIP_CREATE_FAIL)
});
}
resolve({
code: sc.SUCCESS,
json: utils.successTrue(sc.SUCCESS, rm.TRIP_CREATE_SUCCESS)
});
});
},
- create와 다음에 나올 destory를 사용할 때 주의사항은 try catch문 내에서 사용해야 합니다.
- totalDay: totalDay 에서 좌항은 데이터베이스 내 테이블 필드의 실제 이름을 기입해야 하며 우항은 변수이름입니다.
4-3. update
trippingUpdate: ({
id,
}) => {
return new Promise(async (resolve, reject) => {
try {
await Trip.update({
status: 2
}, {
where: {
id: id,
}
});
} catch (error) {
reject({
code: sc.INTERNAL_SERVER_ERROR,
json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.TRIPPING_UPDATE_FAIL)
});
}
resolve({
code: sc.SUCCESS,
json: utils.successTrue(sc.SUCCESS, rm.TRIPPING_UPDATE_SUCCESS)
});
});
},
- 바꿔줄 필드의 값은 create와 동일하고, 바꿔줄 필드의 조건은 findAll에서 사용한 where절과 동일합니다.
4-4. destroy
delete: ({
id
}) => {
return new Promise(async (resolve, reject) => {
try {
trip = await Trip.destroy({
where: {
id: id
}
});
} catch (error) {
reject({
code: sc.INTERNAL_SERVER_ERROR,
json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.TRIP_DELETE_FAIL)
});
}
resolve({
code: sc.SUCCESS,
json: utils.successTrue(sc.SUCCESS, rm.TRIP_DELETE_SUCCESS)
});
});
}
- destroy는 findAll에서 사용한 where과 동일합니다.
추가해야 할 것들
- 1:1, N:M, 한 테이블 내의 N:M
- fn, col
참고
'Node.js' 카테고리의 다른 글
[Sequelize] 반경 내 주위 매장 조회하기 (1) | 2020.06.06 |
---|---|
[Node.js] Express (0) | 2020.01.10 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 클린 코드
- 테라폼
- C++
- 프로그래머스
- Effective Java
- 디자인패턴
- kotest
- Java
- Algorithm
- 객체지향
- Spring
- 백준
- BAEKJOON
- 이팩티브 자바
- AWS
- Kotlin
- 디자인 패턴
- node.js
- Olympiad
- 정규표현식
- 클린 아키텍처
- 코테
- Spring Boot
- MSA
- BOJ
- kkoon9
- 이펙티브 자바
- JPA
- programmers
- 알고리즘
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 28 |
글 보관함