본문 바로가기

WINK-(Web & App)/Express.js (Node.js) 스터디

[2024-2 Node.js 스터디] 김민재 #4주차

반응형

데이터베이스란?


데이터베이스

관련성을 가지며 중복이 없는 데이터들의 집합

  • 데이터베이스를 관리하느 시스템 DBMS
  • DBMS 중 관계형 DBMS인 MySQL을 사용

데이터베이스 및 테이블 생성


데이터베이스 생성

  • CREATE SCHEMA [데이터베이스명]
    • 데이터베이스를 생성하는 명령어이다
    • 스키마는 데이터베이스와 같은 개념이라고 보면 된다
데이터 베이스 생성

CREATE SCHEMA `nodejs` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
'nodejs'라는 이름의 데이터베이스를 생성하고
use nodejs;
를 이용해 nodejs 데이터베이스를 사용하겠다고 알린다
- CREATE SCHEMA 같은 구문은 예악어로 MySQL이 기본적으로 알고 있음, 대문자로 쓰는게 구분하기 쉬움

테이블 생성

  • 테이블이란 데이터가 들어갈 수 있는 틀을 의미하며, 테이블에 맞는 데이터만 들어갈 수 있음
  • CREATE TABLE [데이터베이스명.테이블명]
    • 테이블을 생성하는 명령어이다
테이블 생성

CREATE TABLE nodejs.users (
    -> id INT NOT NULL AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL,
    -> age INT UNSIGNED NOT NULL,
    -> married TINYINT NOT NULL,
    -> comment TEXT NULL,
    -> created_at DATETIME NOT NULL DEFAULT now(),
    -> PRIMARY KEY(id),
    -> UNIQUE INDEX name_UNIQUE (name ASC))
    -> COMMENT = '사용자 정보'
    -> ENGINE = InnoDB;
    
콤마를 이용해 컬럼들을 만들었고, 옵션을 통해 컬럼 규칙에 맞는 정보만 넣을 수 있게 한다.
  • 자료형
    • INT: 정수
    • VARCHAR(자릿수): 가변 길이의 문자열
    • CHAR(자릿수): 고정 길이의 문자열
    • TEXT: 긴 글을 저장할 때 사용
    • TINYINT: -128 ~ 127까지의 정수, 1 또는 0만 저장하면 bool값과 같은 역할 가능
    • DATETIME: 날짜와 시간에 대한 정보
  • 추가 옵션
    • NULL, NOT NULL: 빈칸을 허용할지 여부를 묻는 옵션
    • AUTO_INCREMENT: id 같은 값들을 1씩 올림
    • UNSIGNED: 숫자 자료형에 적용되는 옵션으로, 0 ~ 4294967295이니 나이 같은데 사용하면 좋음
    • ZEROFILL: 자리수 고정되어있을 때 사용
    • DEFAULT now(): created_at에서 해당 컬럼에 값이 없을 때 MySQL이 기본값을 넣음
    • PRIMARY KEY: 해당 컬럼이 기본 키인 경우 고유한 값으로 설정
    • UNIQUE INDEX: 해당 값이 고유해야 하는지에 대한 옵션

-DESCRIBE users;를 이용해 만들어진 테이블을 확인해 봄

사용자의 댓글을 저장하는 테이블

CREATE TABLE nodejs.comments(
    -> id INT NOT NULL AUTO_INCREMENT,
    -> commenter INT NOT NULL,
    -> comment VARCHAR(100) NOT NULL,
    -> created_at DATETIME NOT NULL DEFAULT now(),
    -> PRIMARY KEY(id),
    -> INDEX commenter_idx (commenter ASC),
    -> CONSTRAINT commenter
    -> FOREIGN KEY (commenter)
    -> REFERENCES nodejs.users (id)
    ->  ON DELETE CASCADE
    -> ON UPDATE CASCADE)
    -> COMMENT = '댓글'
    -> ENGINE=InnoDB;
  • commentor 컬럼에 댓글을 작성한 사용자의 id를 저장할 것인데, 다른 테이블의 기본 키를 저장하는 컬럼을 외래 키 (foreign key)라고 한다.
    • → CONSTRAINT commenter → FOREIGN KEY (commenter) → REFERENCES nodejs.users (id)
    • comments 테이블의 commenter 컬럼과 users 테이블의 id 컬럼을 연결했다
  • nodejs 테이블 안에 comments, users 테이블이 잘 만들어진 것을 볼 수 있다!!

CRUD


 

CRUD

Create, Read, Update, Delete의 약자로 데이터베이스에서 많이 수행하는 네 가지 작업임

 

Create (생성)

  • Create는 데이터를 생성해서 데이터베이스에 넣는 작업이다
쿼리를 이용해서 생성하기

 INSERT INTO users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개1');
 이러한 구문으로 데이터를 생성할 수 있다.

Read (조회)

  • Read는 데이터베이스에 있는 데이터를 조회하는 작업이다
쿼리를 이용해 조회하기

SELECT name, age FROM nodejs.users WHERE married = 1 AND age > 30;
SELECT: 컬럼 설정
FROM: 어디에서 가져오는지
WHERE: 조건문 
위와 같은 구문으로 데이터를 테이블에서 조회할 수 있다.

Update (수정)

  • Update는 데이터베이스에 있는 데이터를 수정하는 작업이다
쿼리를 이용해 수정하기

UPDATE nodejs.users SET comment = '바꿀 내용' WHERE id = 2;
WHERE을 사용해 조건문을 통해 어떤 데이터의 comment를 수정할 수 있다.

Delete (삭제)

  • Delete는 데이터베이스에 있는 데이터를 삭제하는 작업이다
쿼리를 이용해 삭제하기

DELETE FROM nodejs.users WHERE id = 2;
조건에 해당하는 로우를 제거할 수 있음

시퀄라이즈


  • 시퀄라이즈 라이브러리를 사용해 JS 구문을 SQL로 바꿔 MySQL을 조작할 수 있다

MySQL 연결하기

  • app.js에서 node와 sql을 연동되도록하고
  • config.json에서 MySQL 정보를 넣어 데이터베이스와 연결 시켰다.

모델 정의하기

  • MySQL에서 정의한 테이블을 시퀄라이즈에서도 정의해야한다
  • User과 Comment 모델을 만들어 users 테이블과 comments 테이블에 연결해보자
**user 모델**
const Sequelize = require('sequelize');

class User extends Sequelize.Model {
  static initiate(sequelize) {
    User.init({
      name: {
        type: Sequelize.STRING(20),
        allowNull: false,
        unique: true,
      },
      age: {
        type: Sequelize.INTEGER.UNSIGNED,
        allowNull: false,
      },
      married: {
        type: Sequelize.BOOLEAN,
        allowNull: false,
      },
      comment: {
        type: Sequelize.TEXT,
        allowNull: true,
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.NOW,
      },
    }, {
      sequelize,
      timestamps: false,
      underscored: false,
      modelName: 'User',
      tableName: 'users',
      paranoid: false,
      charset: 'utf8',
      collate: 'utf8_general_ci',
    });
  }

  static associate(db) {}
};

module.exports = User;

MySQL과 같이 모델을 정의해주고, export를 통해 모듈로 만들었다
user 모델은 Sequelize.Model을 확장한 클래스로 선언하고 
크게 static initiate 메서드와 static associate 메서드로 나눠진다
static initate는 테이블에 대한 설정을 하고
static associate는 다른 모델과의 관계를 적는다

- statice initate
	- 첫번째 인수: 테이블 컬럼에 대한 설정
	- VARCHAR(100)-> STRING(100), INT -> INTEGER 같이 자료형은 조금씩 다름
	
	- 두번째 인수: 테이블 자체에 대한 설정
	- sequelize: db.sequelize 객체를 넣어야 한다
	- timestamps: 수정될 때의 시간이 자동으로 입력
	- underscored:예시로 createdAT -> created_at으로 바꾸는 옵션
	- modelName: 모델 이름을 설정
	- tableName: 실제 데이터베이스의 테이블 이름
	- paranoid: 지운 시각이 기록
	- charset, collate: 한글 입력하고 싶으면 utf8 사용
	
**comment 모델**
const Sequelize = require('sequelize');

class Comment extends Sequelize.Model {
  static initiate(sequelize) {
    Comment.init({
      comment: {
        type: Sequelize.STRING(100),
        allowNull: false,
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: true,
        defaultValue: Sequelize.NOW,
      },
    }, {
      sequelize,
      timestamps: false,
      modelName: 'Comment',
      tableName: 'comments',
      paranoid: false,
      charset: 'utf8mb4',
      collate: 'utf8mb4_general_ci',
    });
  }

  static associate(db) {
    db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });
  }
};

module.exports = Comment;

commneter 컬럼이 없는데, 시퀄라이즈 자체에서 관계를 따로 정의할 수 있음

  • 만든 user과 comment 모델을 db라는 객체에 담아뒀고, db 객체를 require해서 User, Comment 모델에 접근할 수 있다.

관계 정의하기

  • users 테이블과 comments 테이블 간의 관계를 정의해보겠다.
  • 관계의 종류엔 1:1, 1:N, N:N가 있다.
  • MySQL에선 JOIN이라는 기능으로 여러 테이블 간의 관계를 파악해 결과를 도출한다. 또한 시퀄라이즈는 JOIN 기능도 알아서 구현하지만, 테이블 간에 어떠한 관계가 있는지 시퀄라이즈에게 알려야 한다.

1:N

  • hasMany라는 메서드를 이용해 users 테이블 로우 하나를 불러 올때 연결된 comments 테이블의 로우도 같이 불러 올 수 있다.
  • belongsTo라는 메서드를 이용해 comments 테이블의 로우를 불러올 때 연결될 users 테이블의 로우를 가져온다.
    • 다른 모델의 정보가 들어가는 테이블에 belongsTo를 사용하면 된다. 예제에서 comment 모델이 belongsTo를 사용한다.

1:1

  • 1:1에선 hasMany 메서드 대신 hasOne 메서드를 사용한다

N:M

  • belongsToMany 메서드를 사용한다

쿼리 알아보기

  • 시퀄라이즈로 CRUD 작업을 하려면 시퀄라이즈 쿼리를 알아야 한다.
**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',
});

**Read**
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 },
  },
});

**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 모델은 Comment 모델과 hasMany-belongsTo 관계가 맺어져 있다.
만약 특정 사용자를 가져오면서 그 사람의 댓글까지 모두 가져오고 싶다면 include 속성을 사용한다.

const user = await User.findOne({
  include: [{
    model: Comment,
  }]
});
console.log(user.Comments); // 사용자 댓글

어떤 모델과 관계가 있는지를 include 배열에 넣어주면 된다
  • SQL 쿼리하기
    • 시퀄라이즈의 쿼리를 사용하기 싫거나, 어떻게 해야 할지 모르겠다면 SQL문으로 쿼리를 할 수 있다.
const [result, metadata] = await sequelize.query('SELECT * from comments');
console.log(result);
  • 쿼리 수행하기

SQL 구문과 라우터들이 잘 작동하는 것을 볼 수 있다.

 

반응형