IT/Node.js

Sequelize

Huitopia 2021. 12. 25. 02:37
728x90

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);

 

728x90