Sequelize

Sequelize

Sequelize

SQL 작없을 쉽게 할 수 있도록 도와주는 라이브러리

ORM(Object Relational Mapping): 객체와 데이터를 맵핑(1 : 1 짝지음)

mySQL 외에도 다른 RDB(Maria, Postgre, SQLite, MSSQL)와도 호환됨

자바스크립트 문법으로 데이터베이스 조작 가능

Sequelize-cli 사용하기 위한 명령어

% npm i express morgan nunjucks sequlize sequelize-cli mysql2

→ mysql2는 MySQL DB가 아닌 드라이버(Node.js와 MySQL을 이어주는 역할)

% npm i -D nodemon

% npx sequelize init → sequelize 구조 생성

MySQL과 Sequelize의 비교

MySQL Sequelize VARCHAR(100) STRING(100) INT INTEGER TINYINT BOOLEAN DATETIME DATE INT UNSIGNED INTEGER.UNSIGNED NOT NULL allowNull: false UNIQUE unique: true DEFAULT now() defaultValue: Sequelize.NOW

define 메서드의 세번째 인자는 테이블 옵션

timestamp: true면 createdAt(생성 시간), updatedAt(수정 시간) 컬럼을 자동으로 만듦

paranoid 옵션은 true면 deletedAt(삭제 시간) 컬럼을 만듦., 로우 복구를 위해 완전히 삭제하지 않고 deletedAt에 표시해둠

underscored 옵션은 캐멀 케이스로 생성되는 컬럼을 스네이크 케이스로 생성

modelName은 모델 이름, tableName 옵션은 테이블 이름을 설정

charset과 collate는 한글 설정을 위해 필요(이모티콘 넣으려면 utf8mb4로)

테이블 관계 이해하기

users 모델과 comments 모델 간의 관계를 정의 / 1 대 N

1:N 관계 (사용자 한 명이 댓글 여러 개 작성 → 댓글 하나에 사용자가 여러명일 수 없음)

sequelize에서는 1:N 관계를 hasMany로 표현(사용자.hasMany(댓글))

반대의 입장에서는 belongsTo(댓글.belongsTo(사용자))

belongsTo가 있는 테이블에 컬럼이 생김(댓글 테이블에 commenter 컬럼)

1 대 1 관계

ex) 사용자 테이블과 사용자 정보 테이블

db.User.hasOne(db.Info, { foreignKey: 'UserId', sourceKey: 'id' }); db.Info.belongsTo(db.User, { foreignKey: 'UserId', targetKey: 'id' });

다대다 관계

ex) 게시글과 해시태그 테이블 하나의 게시글이 여러개의 해시태그를 가질 수 있고 하나의 해시태그가 여러개의 게시글을 가질 수 있다.

DB 특성상 다대다 관계는 중간 테이블이 생김

db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' }); db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });

N:M 관계 테이블

한 컬럼에 하나만 있어야 하기 때문에(정규화 원칙) 다대다 관계가 생긴다면 중간 테이블이 존재해야한다.

중간 테이블이 존재하지 않는다면 정규화 원칙에 어긋난다.

SQL문과 Sequelize 쿼리의 차이

Create

INSERT INTO nodejs.users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개1');

const { User } = require('../models'); User.create({ name: 'zero', age: 24, married: false, comment: '자기소개1', });

Reade

SELECT * FROM nodejs.users;

User.findAll({});

SELECT name, married From nodejs.users;

User.findAll({ attributes: ['name', 'married'] });

특수한 기능들인 경우 Sequelize.Op의 연산자 사용(gt, or등)

gt >, lt <, gte >=, lte <=, in [a,b,c]

SELECT name, age FROM nodejs.users WHERE married = 1 AND age > 30;

const { Op } = require('sequelize'); const { User } = require('../models'); User.findAll({ attributes: ['name', 'age'], where: { married: true, age: {[Op.gt]: 30}, }, });

SELECT id, name FROM users WHERE married = 0 OR age > 30;

const { Op } = require('sequelize'); const { User } = require('../models'); User.findAll({ attributes: ['id', 'name'], where: { [Op.or]: [{married: false}, {age: {[Op.gt]: 30}], }, });

SELECT id, name FROM users ORDER BY age DESC;

User.findAll({ attributes: ['id', 'name'], // 2차원 배열 [['age', 'DESC'], [createdAt, 'asc']] order: [['age', 'DESC']] });

SELECT id, name FROM users ORDER BY age DESC LIMIT 1;

User.findAll({ attributes: ['id', 'name'], order: [['age', 'DESC']], limit: 1, });

SELECT id, name FROM users ORDER BY age DESC LIMIT 1 OFFSET 1;

User.findAll({ attributes: ['id', 'name'], order: [['age', 'DESC']], limit: 1, offset: 1, });

UPDATE

UPDATE nodejs.users SET comment = '변경 내용' WHERE id = 2;

User.update({ comment: '변경 내용', }, { where: { id: 2 }, });

DELETE

DELETE FROM nodejs.users WHERE id = 2;

User.destory({ where: { id: 2 }, }); User.destory({ // in 활용하여 1,3,5 아이디 지우기 where: { id: {[Op.in]: [1, 3, 5]} }, }); User.destory({ // ne 활용하여 5를 제외한 나머지 아이디 지우기 where: { id: {[Op.ne]: 5} }, });

관계 쿼리

결과값이 자바스크립트 객체일 때

const user = await User.findOne({}); console.log(user.nick); // 사용자 닉네임

include로 join과 비슷한 기능 수행(관계 있는 것 엮기)

const user = await User.findOne({ include: [{ model: Comment, }] }); console.log(user.Comments); // 사용자 댓글 // 사용자 가져오는 동시에 댓글도 가져오기 때문에 성능에 문제있을 수 있음

include나 관계 쿼리 메서드에서도 where나 attributes

const user = await User.findOne({ include: [{ model: Comment, where: { id: 1, }, attributes:['id'], }] }); // OR const comments = await user.getComments({ where: { id: 1, }, attributes: ['id']; }) console.log(user.Comments); // 사용자 댓글

다대다 모델은 다음과 같이 접근

db.sequelize.models.PostHashtag

get+모델명으로 관계 있는 데이터 로딩 가능

const user = await User.findOne({}); const comments = await user.getComments(); console.log(comments); // user 사용자 댓글

as로 모델명 변경 가능

// 관계 설정 시 as로 등록 db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id', as: 'Answers' }); // 쿼리는 const user = await User.findOne({}); const comments = await user.getAnswers(); console.log(comments); // 사용자 댓글

생성 쿼리

const user = await User.findOne({}); const comment = await Comment.create(); await user.addComment(comment); // OR await user.addComment(comment.id);

여러 개를 추가할 때는 배열로 저장

const user = await User.findOne({}); const comment1 = await Comment.create(); const comment2 = await Comment.create(); await user.addComment([comment1, comment2]);

수정은 set+모델명, 삭제는 remove+모델명

직접 SQL문 작성 가능

const [result, metadate] = await sequelize.query('SELECT * from comments'); console.log(result);

from http://cloud-cuckoo-land.tistory.com/81 by ccl(A) rewrite - 2021-12-25 03:00:58