Sequelize ORM
이전 포스팅에서 MVC 모델에 대하여 간략히 정리하였다.
ORM
ORM은 바로 Model을 기술하는 도구이다. 이를 통해 데이터베이스 세계와 프로그래밍 언어 사이의 개념의 간극을 줄여준다(개발자들에겐 객체지향적 프로그래밍이 익숙하므로). 이전에 쇼핑몰 데이터베이스 구축 시 SQL 명령문을 직접 사용하였다면, 이번엔 ORM을 이용하여 SQL 문을 직접 작성하지 않고 엔티티를 객체로 표현하는 방법을 학습해보았다.
Sequelize
- Node.js 기반의 ORM으로 PostgreSQL, MySQL, MariaDB, SQLite, MS-SQL을 지원한다.
- 프로미스 기반의 ORM이기 때문에 비동기 처리에 용이하다.
- table 대신 modeling을 통해 객체 형태로 table을 짠다.
환경 세팅
-
git clone, npm install 을 한다.
-
Sequelize ORM 통해 sequelize 설치
npm install --save sequelize
package.json에 최신버전(v6)으로 설치됐는지 확인한다.
dependencies 항목에 추가되어 있다. -
Sequelize - Migrations 통해 sequelize-cli 를 설치
npm install --save-dev sequelize-cli
마이그레이션을 할 수 있도록 돕는 툴로, CLI에서 모델을 생성해주거나, 스키마 적용을 할 수 있도록 돕는다.
ORM 설정
공식문서를 참고하여 cli를 통해 ORM을 잘 사용할 수 있도록 bootstraping(프로젝트 초기 단계를 자동으로 설정할 수 있도록 도와주는 일)을 해주었다.
npx sequelize-cli init
명령어를 입력하면 네 개의 폴더들이 생성된다.
config/config.json
models/
migrations/
seeders/
그리고 config.json 파일에서 비밀번호를 변경한다.
개발용, 테스트용, 배포용 환경중 개발용 환경을 기본적으로 사용한다.
models폴더 index.js 를 보면
const env = process.env.NODE_ENV || 'development';
해당 코드를 확인할 수 있다.
export NODE_ENV=production
하면 다른 환경으로 바꿀 수 있다.
{
"development": {
"username": "root",
"password": null, // 비밀번호 변경
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
모델 생성
모델은 엔티티를 객체로 표현한 형태로, 데이터 구조를 기술하고, 데이터에 수행할 수 있는 명령의 모음을 의미한다.
1. 데이터베이스 생성
mysql -u root -p mysql
을 실행
CREATE DATABASE database_development;
DB생성
USE database_development;
해당 DB를 사용
- 모델 생성
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
해당 명령어(예시)로 모델을 생성하였다. 모델명과 속성들을 각각 정의해주었다. url, title, visits
필드를 생성하였고, id, createdAt, updatedAt
필드는 자동으로 생성되었다.
마이그레이션
npx sequelize-cli db:migrate
명령어를 실행하여,
마이그레이션을 실행함으로써 데이터베이스에 해당 테이블을 생성해주었다.
- 수정할 사항 있는 경우(기본값 등)
npx sequelize-cli db:migrate:status
해서 상태가 up이면
npx sequelize-cli db:migrate:undo
로 실행취소 , down으로 해놓고 수정후 다시 1번 명령어 실행한다.
models/url.js 에서 init() 부분 내용 수정하고,
migrations/ 파일에서도 내용을 수정해야 한다.
스키마 변경이 있을 때마다 마이그레이션을 실행해줘야 한다.
bitly model 구현해보기
https://bitly.com/ bitly는 긴 url을 축약해서 짧게 만들어주는 어플리케이션니다. 이 어플리케이션의 모델파트를 구현해보았다.
일단 구현해야 하는 내용을 간단히 하자면 아래와 같다.
스프린트에서 직접 사용하였던 sequlize 기본 메소드
sequlize 메소드는 기본적으로 모두 promise 객체를 반환한다. 따라서 객체 내 result 값을 꺼내오려면 .then
이나 async/await
을 사용해야 한다.
fineAll();
GET/links 요청을 처리할 때 사용하였다. sql구문에서 SELECT * FROM TABLE
과 똑같은 처리를 한다.
const { url: URLModel } = require("../../models"); //먼저 모델폴더에서 url 모델객체를 가져온다
get: async (req, res) => {
const result = await URLModel.findAll();
res.status(200).json(result);
},
findOrCreate();
POST/links 요청을 처리할 때 사용하였다. 요청의 payload에 아래와 같이 단축시키고 싶은 URL이 url 속성에 담겨있다. findOrCreate 메소드는 해당데이터를 찾고 그 조회 결과가 없는 경우에 엔트리를 테이블에 추가한다. create는 sql 구문에서 INSERT INTO ___ VALUES___
와 똑같은 처리를 한다.
{
"url": "https://www.github.com"
}
const [result, created] = await URLModel.findOrCreate({
where: {
url,
},
default: {
title,
},
});
if (created) {
return res.status(201).json(result); // 새로 생성된 경우 create
}
res.status(201).json(result); // 조회한 경우 find
findOne();
GET /links/:id 요청을 처리할 때 사용하였다. findOne 메소드는 조건을 만족하는 첫번째 엔트리를 찾아낸다.
해당 id 값 바탕으로 url 모델을 찾아 리디렉션해주었다.
ex) 원본 URL이 https://www.github.com 인 모델 id가 1일 경우, http://localhost:3000/links/1 로 접속하면 원본 URL로 리디렉션
const result = await URLModel.findOne({
where: {
id: urlId,
},
});
update();
/links/:id URL로 접근할 경우 visits 필드에 카운트가 1씩 증가해줘야 하는데 그 때 필드값을 업데이트 해주는 해당 메소드를 사용하였다.
await result.update({
visits: result.visits + 1,
});
association을 이용한 join table 구현
1. users 테이블 생성 & 마이그레이션
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
cli 명령어를 입력하여 새로운 모델을 생성하고, npx sequelize-cli db:migrate
명령어를 실행하여, 마이그레이션 해주었다.
2. 새 마이그레이션 파일을 생성하여 urls 테이블에 필드추가 & FK 설정하기
npx sequelize-cli migration:create --name addUserIdColumn
명령어를 입력하여 새로운 마이그레이션 파일을 생성하였다. up/down 속성이 비워진 상태로 새 마이그레이션 파일(Migration Skeleton)이 생성되었다.
해당 마이그레이션 파일내에서 아래와 같이 up/down 속성을 정의해주었다.(field 추가 & FK 설정)
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
// field 추가
await queryInterface.addColumn('urls', 'userId', Sequelize.INTEGER);
// foreign key 연결
await queryInterface.addConstraint('urls', {
fields: ['userId'],
type: 'foreign key',
name: 'FK_any_name_you_want',
references: {
table: 'users',
field: 'id'
},
onDelete: 'cascade',
onUpdate: 'cascade'
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.removeConstraint('urls', 'FK_any_name_you_want');
await queryInterface.removeColumn('urls', 'userId');
}
};
3. 1:N 관계 만들기
/models/index.js 파일에서 아래와 같이 associations를 설정해주었다. (user:url = 1:N)
const { url, user } = sequelize.models;
url.belongsTo(user);
user.hasMany(url);
Author And Source
이 문제에 관하여(Sequelize ORM), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@devjade/Sequelize-ORM저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)