Node.js 섹션 6 MySQL

_upper·2023년 11월 7일

MYSQL 설치하기

데이터베이스란

지금까지는 데이터를 서버 메모리에 저장했음

  • 서버를 재시작하면 데이터 사라져버림 -> 영구적으로 저장할 공간 필요

MySQL 관계형 데이터베이스 사용

  • 데이터베이스: 관련성을 가지며 중복이 없는 데이터들의 집합
  • DBMS: 데이터베이스를 관리하는 시스템
  • RDBMS: 관계형 데이터베이스를 관리하는 시스템
  • 서버의 하드 디스크나 SSD 등의 저장 매체에 데이터를 저장
  • 서버 종류 여부와 상관 없이 데이터를 계속 사용할 수 있음
  • 여러 사람이 동시에 접근할 수 있고, 권한을 따로 줄 수 있음

mysql, 워크벤치 설치하기

공식사이트

https://dev.mysql.com/downloads/installer/

Choosing s Setup Type -> Custom

Selecct Products and Features -> server, workbench 추가


테이블 만들기

데이터베이스 생성하기

콘솔에서 MySQL 프롬프트에 접속

  • CREATE SCHEMA node.js;로 nodejs 데이터베이스 생성
  • use nodejs;로 생성한 데이터베이스 선택

테이블 생성하기

MySQL 프롬프트에서 테이블 생성

  • CREATE TABLE [데이터베이스명.테이블명]으로 테이블 생성
  • 사용자 정보를 저장하는 테이블

컬럼과 로우

나이, 결혼 여부, 성별같은 정보가 컬럼

실제로 들어가는 데이터는 로우

컬럼 옵션들

id INT NOT NULL AUTO_INCREMENT

  • INT: 정수 자료형입니다.
  • VARCHAR: 문자열 자료형입니다. 가변 길이입니다.
  • TEXT: 문자열 자료형입니다. 고정 길이가 아닙니다.
  • DATETIME: 날짜와 시간을 나타내는 자료형입니다.
  • TINYINT: 정수 자료형입니다. -128에서 127까지 저장할 수 있습니다.
  • NOT NULL: 빈 값을 허용하지 않습니다.
  • AUTO_INCREMENT: 숫자 자료형인 경우 다음 로우가 저장될 때 자동으로 1씩 증가합니다.
  • UNSIGNED: 0과 양수만 허용합니다.
  • ZEROFILL: 숫자의 자리 수가 고정된 경우 빈 자리에 0을 채웁니다.
  • DEFAULT now(): 날짜 컬럼의 기본값을 현재 시간으로 설정합니다.

칼럼의 옵션들

댓글 테이블 저장하기

commments 테이블 생성

외래키(foreign key)

댓글 테이블은 사용자 테이블과 관계가 있음(사용자가 댓글을 달기 때문)

  • FOREIGN KEY (컬럼명) REFERENCES 데이터베이스.테이블명 (컬럼)
  • FOREIGN KEY (commenter) REFERENCES nodejs.users (id)
  • 댓글 테이블에는 commenter 컬럼이 생기고 사용자 테이블의 id값이 저장됨
  • ON DELETE CASCADE, ON UPDATE CASCADE
  • 사용자 테이블의 로우가 지워지고 수정될 때 댓글 테이블의 연관된 로우들도 같이 지워지고 수정됨
  • 데이터를 일치시키기 위해 사용하는 옵션(CASCADE 대신 SET NULL과 NO ACTION도 있음)

테이블 목록보기


CRUD 작업하기

CRUD

Create, Read, Update, Delete의 두문자어

  • 데이터베이스에서 많이 하는 작업 4가지

Create

INSERT INTO 테이블(컬럼명들) VALUES(값들)

Read

SELECT 컬럼 FROM 테이블명

  • SELECT * 은 모든 컬럼을 선택한다는 의미
SELECT * FROM nodejs.users;
  • 컬럼만 따로 추리는 것도 가능
SELECT name, married FROM nodejs.users;

Read 옵션들

WHERE로 조건을 주어 선택가능

  • AND로 여러가지 조건을 동시에 만족하는 것을 찾음
SELECT name, age FROM nodejs.users WHERE married = 1 AND age > 30l;
  • OR로 여러가지 조건 중 하나 이상을 만족하는 것을 찾음
SELECT id, name FROM nodejs.users WHERE married = 0 OR age > 30;

ORDER BY로 특정 컬럼 값 순서대로 정렬 가능

  • DESC는 내림차순, ASC는 오름차순
SELECT id, name FROM nodejs.users ORDER BY age DESC;

LIMIT, OFFSET

LIMIT으로 조회할 개수 제한

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

OFFSET으로 앞의 로우들 스킵 가능(OFFSET 2면 세 번째 것부터 찾음)

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

Update

데이터베이스에 있는 데이터를 수정하는 작업

  • UPDATE 테이블명 SET 컬럼 = 새값 WHERE 조건
UPDATE nodejs.users SET comment = '바꿀 내용' WHERE id = 2;

Delete

데이터베이스에 있는 데이터를 삭제하는 작업

  • DELETE FROM 테이블명 WHERE 조건
DELETE FROM nodejs.users WHERE id = 2;

시퀄라이즈 사용하기

시퀄라이즈 ORM

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

  • ORM: Object Relational Mapping: 객체와 데이터를 매핑(1대1 짝지음)
  • MySQL 외에도 다른 RDB(Maria, Postgre, SQLite, MSSQL)와도 호환됨
  • 자바스크립트 문법으로 데이터베이스 조작 가능

시퀄라이즈 예제: https://github.com/zerocho/nodejs-book/tree/master/ch7/7.6/learn-sequelize

  • 프로젝트 세팅 후, 콘솔을 통해 경로로 이동한 후 package.json 작성

시퀄라이즈 CLI 사용하기

시퀄라이즈 명령어 사용하기 위해 sequelize-cli 설치

  • mysql2는 MySQL DB가 아닌 드라이버(Node.js와 MySQL을 이어주는 역할)
$ npm i express morgan nunjucks sequelize sequelize-cli mysql2
$ npm i-D nodemon

npx sequelize init으로 시퀄라이즈 구조 생성

$ npx sequelize init

modes/index.js 수정

다음과 같이 수정

  • require(../config/config) 설정 로딩
  • new Sequelize(옵션들...)로 DB와 연결 가능

MySQL 연결하기

app.js 작성

  • sequelize.sync로 연결

연결 테스트하기

npm start로 실행해서 SELECT 1+1 AS RESULT가 나오면 연결 성공


시퀄라이즈 모델 만들기

모델 옵션들

시퀄라이즈 모델의 자료형은 MySQL의 자료형과 조금 다름

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

알겠습니다. 사진 속 글자를 똑같이 적어 보겠습니다.

  • timestamps: true면 createdAt(생성 시간), updatedAt(수정 시간) 컬럼을 자동으로 만듦
  • 예제에서는 직접 created_at 컬럼을 만들었으므로 false로 함
  • paranoid 옵션은 true면 deletedAt(삭제 시간) 컬럼을 만듦, 로우 복구를 위해 완전히 삭제하지 않고 deletedAt에 표시해둠
  • underscored 옵션은 캐멀케이스로 생성되는 컬럼을 스네이크케이스로 생성
  • modelName은 모델 이름, tableName 옵션은 테이블 이름을 설정
  • charset과 collate는 한글 설정을 위해 필요(이모티콘 넣으려면 utf8mb4)

댓글 모델 생성하기

comment.js 생성

댓글 모델 활성화하기

index.js에 모델 연결

  • init으로 sequelize와 연결
  • associate로 관계 설정
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');

db.sequelize = sequelize;
db.User = User;
db.Comment = Comment;

User.init(sequelize);
Comment.init(sequelize);

User.associate(db);
Comment.associate(db);

module.exports = db;

테이블 관계 이해하기

관계 정의하기

users 모델과 comments 모델 간의 관계를 정의

  • 1:N 관계 (사용자 한 명이 댓글 여러 개 작성)
  • 시퀄라이즈에서는 1:N 관계를 has Many로 표현(사용자.hasMany(댓글))
  • 반대의 입장에서는 belongsTo(댓글.belongsTo(사용자))
  • belongsTo가 있는 테이블에 컬럼이 생김(댓글 테이블에 commenter 컬럼)

1대1 관계

1대1 관계

  • 예) 사용자 테이블과 사용자 정보 테이블
db.User.hasOne(db.Info, { foreignKey: 'UserId', sourcekey: 'id' });
db.Info.belongsTo(db.User, { foreignkey: 'UserId', targetKey: 'id' });

N대N 관계

다대다 관계

  • 예) 게시글과 해시태그 테이블
  • 하나의 게시글이 여러 개의 해시태그를 가질 수 있고 하나의 해시태그가 여러 개의 게시글을 가질 수 있음
  • DB 특성상 다대다 관계는 중간 테이블이 생김
db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' });
db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });

관계 쿼리 알아보기

관계 쿼리

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

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

include JOIN 과 비슷한 기능 수행 가능(관계 있는 것 엮을 수 있음)

const user = await User.findOne({

	include: [{

		model: Comment,

	}]

});

console.log(user.Comments); // 사용자 댓글

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

db.sequelize.models.PostHashtag

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

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

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); // 사용자 댓글

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

const user = await User.findOne({
  include: [{
    model: Comment,
    where: {
      id: 1,
    },
    attributes: ['id'],
  }],
});

// 또는

const comments = await user.getComments({
  where: {
    id: 1,
  },
  attributes: ['id'],
});

생성 쿼리

const user = await User.findOne({});
const comment = await Comment.create();
await user.addComment(comment);
// 또는
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+모델명

raw 쿼리

직접 SQL을 쓸 수 있음

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

시퀄라이즈 쿼리 알아보기

시퀄라이즈 쿼리 알아보기

윗 줄이 SQL문, 아랫 줄은 시퀄라이즈 쿼리(자바스크립트)

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

수정

UPDATE nodejs.users SET comment='48' WHERE id = 2;
User.update({
	comment: '바꿀 내용',
}, {
	where: { id: 2 },
});

삭제

DELETE FROM nodejs.users WHERE id = 2;
User.destroy({
	where: { id: 2 },
});

시퀄라이즈 실습하기

쿼리 수행하기

users 라우터

  • get, post, delete, patch 같은 요청에 대한 라우터 연결
  • 데이터는 JSON 형식으로 응답
  • comments 라우터도 마찬가지

comments 라우터

const express = require('express');
const { User, Comment } = require('../models');

const router = express.Router();

router.post('/', async (req, res, next) => {
  try {
    const comment = await Comment.create({
      commenter: req.body.id,
      comment: req.body.comment,
    });

    res.status(201).json(comment);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

router.patch('/:id', async (req, res, next) => {
  try {
    const result = await Comment.update({
      comment: req.body.comment,
    }, { where: { id: req.params.id } });

    res.json(result);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

router.delete('/:id', async (req, res, next) => {
  try {
    const result = await Comment.destroy({ where: { id: req.params.id } });

    res.json(result);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

module.exports = router;

서버 접속하기

npm start로 서버 시작

  • localhost:3000 으로 접속하면 시퀄라이즈가 수행하는 SQL문이 콘솔에 찍힘

1개의 댓글

comment-user-thumbnail
2023년 11월 8일

잘보고 갑니다.~

답글 달기