์ƒ์„ธ ์ปจํ…์ธ 

๋ณธ๋ฌธ ์ œ๋ชฉ

[๋…ธ๋“œ 2] 7์žฅ. MySQL

23-24/Node.js 2

by _๋„๋‹ด 2023. 11. 17. 10:00

๋ณธ๋ฌธ

728x90

 

๐ŸŒŸ7์žฅ ํ‚ค์›Œ๋“œ๐ŸŒŸ

MySQL

์›Œํฌ๋ฒค์น˜

CRUD

์‹œํ€„๋ผ์ด์ฆˆ

 

 

์„œ๋ฒ„๋ฅผ ์ข…๋ฃŒํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋  ์ˆ˜ ์žˆ๋„๋ก ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ™œ์šฉํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

7.1 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ž€?

 

๐Ÿ“Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

  • ๊ด€๋ จ์„ฑ์„ ๊ฐ€์ง€๋ฉฐ ์ค‘๋ณต์ด ์—†๋Š” ๋ฐ์ดํ„ฐ๋“ค์˜ ์ง‘ํ•ฉ
  • ์„œ๋ฒ„์˜ ํ•˜๋“œ ๋””์Šคํฌ๋‚˜ SSD๋“ฑ์˜ ์ €์žฅ ๋งค์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ
  • ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์‹œ์— ์‚ฌ์šฉ

 

7.2 MySQL ์„ค์น˜ํ•˜๊ธฐ

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

 

MySQL :: Download MySQL Installer

Note: MySQL 8.0 is the final series with MySQL Installer. As of MySQL 8.1, use a MySQL product's MSI or Zip archive for installation. MySQL Server 8.1 and higher also bundle MySQL Configurator, a tool that helps configure MySQL Server.

dev.mysql.com

[Node.js ๊ต๊ณผ์„œ] ์ฐธ๊ณ 

 

7.3 ์›Œํฌ๋ฒค์น˜ ์„ค์น˜ํ•˜๊ธฐ

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

 

MySQL :: Download MySQL Workbench

Select Operating System: Select Operating System… Microsoft Windows Ubuntu Linux Red Hat Enterprise Linux / Oracle Linux Fedora macOS Source Code Select OS Version: All Windows (x86, 64-bit) Recommended Download: Other Downloads: Windows (x86, 64-bit), M

dev.mysql.com

[Node.js ๊ต๊ณผ์„œ] ์ฐธ๊ณ 

 

7.4 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ํ…Œ์ด๋ธ” ์ƒ์„ฑํ•˜๊ธฐ

 

๐Ÿ“Œ MySQL ์ž๋ฃŒํ˜•

์ž๋ฃŒํ˜• ์˜๋ฏธ ๋น„๊ณ 
INT ์ •์ˆ˜ ์†Œ์ˆ˜๊นŒ์ง€ ์ €์žฅ : FLOAT, DOUBLE
VARCHAR ์ž๋ฆฟ์ˆ˜ ๊ฐ€๋ณ€๊ธธ์ด
CHAR ์ž๋ฆฟ์ˆ˜ ๊ณ ์ •๊ธธ์ด, ๋ถ€์กฑํ•œ ์ž๋ฆฟ์ˆ˜๋Š” ์ŠคํŽ˜์ด์Šค๋กœ ์ฑ„์šด๋‹ค.
TEXT ๊ธด ๊ธ€ ์ˆ˜๋ฐฑ ์ž ์ด์ƒ
TINYINT -128~127๊นŒ์ง€์˜ ์ •์ˆ˜ Boolean ๋Œ€์‹  ์‚ฌ์šฉ
DATETIME, DATE, TIME ๋‚ ์งœ์™€ ์‹œ๊ฐ„  

 

๐Ÿ“Œ ์ปฌ๋Ÿผ ์˜ต์…˜

์˜ต์…˜ ๋น„๊ณ 
PRIMARY KEY (PR) ๊ธฐ๋ณธํ‚ค
NULL, NOT NULL (NN) NULL ํ—ˆ์šฉ ์—ฌ๋ถ€
UNIQUE INDEX (UQ) ๊ณ ์œ ๊ฐ’
BINARY (B) ๋ฐ์ดํ„ฐ๋ฅผ ์ด์ง„ ๋ฌธ์ž์—ด๋กœ ์ €์žฅ
UNSIGNED (UN) ์Œ์ˆ˜๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ˆซ์ž ์ €์žฅ,
FLOAT์™€ DOUBLE์—๋Š” ์ ์šฉ ๋ถˆ๊ฐ€๋Šฅ
ZEROFILL (ZF) ์ˆซ์ž์˜ ์ž๋ฆฟ์ˆ˜๋ฅผ ๊ณ ์ •
INT(4)์— 1 ์ €์žฅ → 0001
AUTO_INCREMENT (AI) ์ˆซ์ž๋ฅผ ์ž๋™์œผ๋กœ ์ฆ๊ฐ€
GENERATED COLUMN (G) ๋‹ค๋ฅธ ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์ˆ˜์‹์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฐ’

 

 

๐Ÿ“Œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ

users ํ…Œ์ด๋ธ”
comments ํ…Œ์ด๋ธ”
comments ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ์„ค์ •

 

7.6 ์‹œํ€„๋ผ์ด์ฆˆ ์‚ฌ์šฉํ•˜๊ธฐ

 

๐Ÿ“Œ ์‹œํ€„๋ผ์ด์ฆˆ

  • ๋…ธ๋“œ์—์„œ MySQL ์ž‘์—…์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ORM์œผ๋กœ ๋ถ„๋ฅ˜

๐Ÿ“Œ ORM

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฆด๋ ˆ์ด์…˜์„ ๋งคํ•‘ํ•ด ์ฃผ๋Š” ๋„๊ตฌ
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ตฌ๋ฌธ์„ ์•Œ์•„์„œ SQL๋กœ ๋ฐ”๊ฟˆ
  • SQL ์–ธ์–ด๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋งŒ์œผ๋กœ MySQL ์กฐ์ž‘

๐Ÿ“Œ ํŒจํ‚ค์ง€ ์„ค์น˜ ๋ฐ ํ˜ธ์ถœ

npm i express morgan nunjucks sequelize sequelize-cli mysql2
npm i -D nodemon
npx sequelize init

 

7.6.1 MySQL ์—ฐ๊ฒฐํ•˜๊ธฐ

โœ”  app.js๋ฅผ ํ†ตํ•ด ์ต์Šคํ”„๋ ˆ์Šค์™€ ์‹œํ€„๋ผ์ด์ฆˆ ์—ฐ๊ฒฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ

 

1๏ธโƒฃ models/index.js ํ™•์ธ

const Sequelize = require('sequelize');

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};

const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;

module.exports = db;

 

  • Sequelize ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์™€ new Sequelize๋ฅผ ํ†ตํ•ด MySQL ์—ฐ๊ฒฐ ๊ฐ์ฒด ์ƒ์„ฑ
  • ๋‚˜์ค‘์— ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€์ˆ˜ db.sequelize์— ์ €์žฅ

 

2๏ธโƒฃ config/config.json ํ™•์ธ

{
  "development": {
    "username": "์‚ฌ์šฉ์ž ์ด๋ฆ„",
    "password": "๋น„๋ฐ€๋ฒˆํ˜ธ",
    "database": "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ช…",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  ...
}
  • MySQL๊ณผ ์—ฐ๋™ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์ •๋ณด
  • test, production์€ ๊ฐ๊ฐ ํ…Œ์ŠคํŠธ์™€ ๋ฐฐํฌ ์šฉ๋„๋กœ ์ ‘์†ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

 

3๏ธโƒฃ app.js ์ž‘์„ฑ

๋”๋ณด๊ธฐ
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const nunjucks = require('nunjucks');

const { sequelize } = require('./models');

const app = express();
app.set('port', process.env.PORT || 3001);
app.set('view engine', 'html');
nunjucks.configure('views', {
  express: app,
  watch : true,
});
sequelize.sync({force: false})
.then(() => {
  console.log('๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ฑ๊ณต');
})
.catch((err) => {
  console.error(err);
});

app.use(morgan('dev'));
app.use('/', express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use((req, res, next) => {
  const error = new Error(`${req.method} ${req.url} ๋ผ์šฐํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.`);
  error.status = 404;
  next(error);
});

app.use((err, req, res, next) => {
  res.locals.message = err.message;
  res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
  res.status(err.status || 500);
  res.render('error');
});

app.listen(app.get('port'), () => {
  console.log(app.get('port'), '๋ฒˆ ํฌํŠธ์—์„œ ๋Œ€๊ธฐ ์ค‘');
});

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™ ์™„๋ฃŒ

 

7.6.2 ๋ชจ๋ธ ์ •์˜ํ•˜๊ธฐ

โœ”  MySQL์—์„œ ์ •์˜ํ•œ ํ…Œ์ด๋ธ”์„ ์‹œํ€„๋ผ์ด์ฆˆ์—์„œ๋„ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โœ”  MySQL์˜ ํ…Œ์ด๋ธ”์€ ์‹œํ€„๋ผ์ด์ฆˆ์˜ ๋ชจ๋ธ๊ณผ ๋Œ€์‘๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“user.js, comment.js ์ž‘์„ฑ

  • User ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด ๋ชจ๋“ˆ๋กœ exports
  • Sequelize.Model์„ ํ™•์žฅํ•œ ํด๋ž˜์Šค๋กœ ์„ ์–ธ

๐Ÿ“๋ชจ๋ธ ์ž‘์„ฑ๋ฒ•

  • static initiate : ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์„ค์ •
  • static associate : ๋‹ค๋ฅธ ๋ชจ๋ธ๊ณผ์˜ ๊ด€๊ณ„ ์ž‘์„ฑ

๐Ÿ“ํ…Œ์ด๋ธ” ์˜ต์…˜

MySQL ์‹œํ€„๋ผ์ด์ฆˆ
VARCHAR(100) STRING(100)
INT INTEGER
TINYINT BOOLEAN
DATETIME DATE
NOT NULL allowNull: false
UNIQUE unique: true
DEFAULT now() defaultValue: Sequelize.NOW

 

๐Ÿ“index.js ์ˆ˜์ •

const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};

const sequelize = new Sequelize(config.database, config.username, config.password, config);

db.sequelize = sequelize;

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

User.initiate(sequelize);   // ๊ฐ๊ฐ์˜ ๋ชจ๋ธ์˜ static initaiate ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
Comment.initiate(sequelize);

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

module.exports = db;

โ–ถ๏ธ db ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์„œ User์™€ Comment ๋ชจ๋ธ์— ์ ‘๊ทผ

 

7.6.3 ๊ด€๊ณ„ ์ •์˜ํ•˜๊ธฐ

โœ”  user์™€ comments ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„ ์ •์˜

1 : N

  • ์‚ฌ์šฉ์ž๊ฐ€ 1, ๋Œ“๊ธ€์ด N
  • ์‹œํ€„๋ผ์ด์ฆˆ์—์„œ๋Š” hasMany๋กœ ํ‘œํ˜„

โœ” ๋ชจ๋ธ ๊ฐ๊ฐ์˜ static associate์— ์ถ”๊ฐ€

โœ” ์ˆœํ™˜์ฐธ์กฐ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ db ๋งค๊ฐœ๋ณ€์ˆ˜ ์‚ฌ์šฉ

 

๐Ÿ“hasMany์™€ belongsTo

  • ๋‹ค๋ฅธ ๋ชจ๋ธ์˜ ์ •๋ณด๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ํ…Œ์ด๋ธ”์—๋Š” belongsTo๋ฅผ ์‚ฌ์šฉ
  • hasMany ๋ฉ”์„œ๋“œ : sourceKey ⇒ id
  • belongsTo ๋ฉ”์„œ๋“œ : targetKey ⇒ id

1 : 1

๐Ÿ“hasOne๊ณผ belongsTo

N : M

๐Ÿ“belongsToMany์™€ belongsToMany

  • though ์†์„ฑ ์‚ฌ์šฉ

 

7.6.5 ์ฟผ๋ฆฌ ์ˆ˜ํ–‰ํ•˜๊ธฐ

โœ” ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋“ฑ๋กํ•œ ๋Œ“๊ธ€์„ ๊ฐ€์ ธ์˜ค๋Š” ์„œ๋ฒ„๋ฅผ ์ œ์ž‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

1๏ธโƒฃ sequelize.js ํŒŒ์ผ ์ƒ์„ฑ

๋”๋ณด๊ธฐ
// ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๋ˆŒ๋ €์„ ๋•Œ ๋Œ“๊ธ€ ๋กœ๋”ฉ
document.querySelectorAll('#user-list tr').forEach((el) => {
    el.addEventListener('click', function () {
      const id = el.querySelector('td').textContent;
      getComment(id);
    });
  });
  // ์‚ฌ์šฉ์ž ๋กœ๋”ฉ
  async function getUser() {
    try {
      const res = await axios.get('/users');
      const users = res.data;
      console.log(users);
      const tbody = document.querySelector('#user-list tbody');
      tbody.innerHTML = '';
      users.map(function (user) {
        const row = document.createElement('tr');
        row.addEventListener('click', () => {
          getComment(user.id);
        });
        // ๋กœ์šฐ ์…€ ์ถ”๊ฐ€
        let td = document.createElement('td');
        td.textContent = user.id;
        row.appendChild(td);
        td = document.createElement('td');
        td.textContent = user.name;
        row.appendChild(td);
        td = document.createElement('td');
        td.textContent = user.age;
        row.appendChild(td);
        td = document.createElement('td');
        td.textContent = user.married ? '๊ธฐํ˜ผ' : '๋ฏธํ˜ผ';
        row.appendChild(td);
        tbody.appendChild(row);
      });
    } catch (err) {
      console.error(err);
    }
  }
  // ๋Œ“๊ธ€ ๋กœ๋”ฉ
  async function getComment(id) {
    try {
      const res = await axios.get(`/users/${id}/comments`);
      const comments = res.data;
      const tbody = document.querySelector('#comment-list tbody');
      tbody.innerHTML = '';
      comments.map(function (comment) {
        // ๋กœ์šฐ ์…€ ์ถ”๊ฐ€
        const row = document.createElement('tr');
        let td = document.createElement('td');
        td.textContent = comment.id;
        row.appendChild(td);
        td = document.createElement('td');
        td.textContent = comment.User.name;
        row.appendChild(td);
        td = document.createElement('td');
        td.textContent = comment.comment;
        row.appendChild(td);
        const edit = document.createElement('button');
        edit.textContent = '์ˆ˜์ •';
        edit.addEventListener('click', async () => { // ์ˆ˜์ • ํด๋ฆญ ์‹œ
          const newComment = prompt('๋ฐ”๊ฟ€ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”');
          if (!newComment) {
            return alert('๋‚ด์šฉ์„ ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค');
          }
          try {
            await axios.patch(`/comments/${comment.id}`, { comment: newComment });
            getComment(id);
          } catch (err) {
            console.error(err);
          }
        });
        const remove = document.createElement('button');
        remove.textContent = '์‚ญ์ œ';
        remove.addEventListener('click', async () => { // ์‚ญ์ œ ํด๋ฆญ ์‹œ
          try {
            await axios.delete(`/comments/${comment.id}`);
            getComment(id);
          } catch (err) {
            console.error(err);
          }
        });
        // ๋ฒ„ํŠผ ์ถ”๊ฐ€
        td = document.createElement('td');
        td.appendChild(edit);
        row.appendChild(td);
        td = document.createElement('td');
        td.appendChild(remove);
        row.appendChild(td);
        tbody.appendChild(row);
      });
    } catch (err) {
      console.error(err);
    }
  }
  // ์‚ฌ์šฉ์ž ๋“ฑ๋ก ์‹œ
  document.getElementById('user-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const name = e.target.username.value;
    const age = e.target.age.value;
    const married = e.target.married.checked;
    if (!name) {
      return alert('์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”');
    }
    if (!age) {
      return alert('๋‚˜์ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”');
    }
    try {
      await axios.post('/users', { name, age, married });
      getUser();
    } catch (err) {
      console.error(err);
    }
    e.target.username.value = '';
    e.target.age.value = '';
    e.target.married.checked = false;
  });
  // ๋Œ“๊ธ€ ๋“ฑ๋ก ์‹œ
  document.getElementById('comment-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const id = e.target.userid.value;
    const comment = e.target.comment.value;
    if (!id) {
      return alert('์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”');
    }
    if (!comment) {
      return alert('๋Œ“๊ธ€์„ ์ž…๋ ฅํ•˜์„ธ์š”');
    }
    try {
      await axios.post('/comments', { id, comment });
      getComment(id);
    } catch (err) {
      console.error(err);
    }
    e.target.userid.value = '';
    e.target.comment.value = '';
  });

๐Ÿ“Œ script ํƒœ๊ทธ์—๋Š” ๋ฒ„ํŠผ๋“ค์„ ๋ˆŒ๋ €์„ ๋•Œ ์„œ๋ฒ„์˜ ๋ผ์šฐํ„ฐ๋กœ AJAX ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด์žˆ์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ ๋ผ์šฐํ„ฐ ์ƒ์„ฑ

โœ” sequelize.js์— ๋‚˜์˜ค๋Š” GET, POST, PUT, DELETE ์š”์ฒญ์— ํ•ด๋‹นํ•˜๋Š” ๋ผ์šฐํ„ฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

โœ” routes ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ์•ˆ์— index.js, users.js, comments.js๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“ index.js

๋”๋ณด๊ธฐ
const express = require('express');
const User = require('../models/user');

const router = express.Router();

router.get('/', async (req, res, next) => {
  try {
    const users = await User.findAll();
    res.render('sequelize', { users });
  } catch (err) {
    console.error(err);
    next(err);
  }
});

module.exports = router;

 

๐Ÿ“ users.js

๋”๋ณด๊ธฐ
const express = require('express');
const User = require('../models/user');
const Comment = require('../models/comment');

const router = express.Router();

router.route('/')
  .get(async (req, res, next) => {
    try {
      const users = await User.findAll();
      res.json(users);
    } catch (err) {
      console.error(err);
      next(err);
    }
  })
  .post(async (req, res, next) => {
    try {
      const user = await User.create({
        name: req.body.name,
        age: req.body.age,
        married: req.body.married,
      });
      console.log(user);
      res.status(201).json(user);
    } catch (err) {
      console.error(err);
      next(err);
    }
  });

router.get('/:id/comments', async (req, res, next) => {
  try {
    const comments = await Comment.findAll({
      include: {
        model: User,
        where: { id: req.params.id },
      },
    });
    console.log(comments);
    res.json(comments);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

module.exports = router;

 

๐Ÿ“ comments.js

๋”๋ณด๊ธฐ
const express = require('express');
const { 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,
    });
    console.log(comment);
    res.status(201).json(comment);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

router.route('/:id')
  .patch(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);
    }
  })
  .delete(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;

 

3๏ธโƒฃ app.js์— ๋ผ์šฐํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ
...
const { sequelize } = require('./models');
const indexRouter = require('./routes');
const usersRouter = require('./routes/users');
const commentsRouter = require('./routes/comments');

const app = express();
...
app.use(express.urlencoded({ extended: false }));

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/comments', commentsRouter);

 

 


๋นˆ์นธ ์ฑ„์šฐ๊ธฐ ๋ฌธ์ œ (๋นˆ์นธ์„ ๋“œ๋ž˜๊ทธํ•ด์„œ ์ •๋‹ต์„ ๋งžํ˜€ ๋ณด์„ธ์š”!)

1. ๊ด€๋ จ์„ฑ์„ ๊ฐ€์ง€๋ฉฐ ์ค‘๋ณต์ด ์—†๋Š” ๋ฐ์ดํ„ฐ๋“ค์˜ ์ง‘ํ•ฉ์„ (๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค)๋ผ๊ณ  ํ•œ๋‹ค.

2. MySQL์˜ ์ž๋ฃŒํ˜•์„ ์ฑ„์šฐ์‹œ์˜ค.

์ž๋ฃŒํ˜• ์˜๋ฏธ ๋น„๊ณ 
INT ์ •์ˆ˜ ์†Œ์ˆ˜๊นŒ์ง€ ์ €์žฅ : FLOAT, DOUBLE
VARCHAR ์ž๋ฆฟ์ˆ˜ ๊ฐ€๋ณ€๊ธธ์ด
CHAR ์ž๋ฆฟ์ˆ˜ ๊ณ ์ •๊ธธ์ด, ๋ถ€์กฑํ•œ ์ž๋ฆฟ์ˆ˜๋Š” ์ŠคํŽ˜์ด์Šค๋กœ ์ฑ„์šด๋‹ค.
TEXT ๊ธด ๊ธ€ ์ˆ˜๋ฐฑ ์ž ์ด์ƒ
TINYINT -128~127๊นŒ์ง€์˜ ์ •์ˆ˜ Boolean ๋Œ€์‹  ์‚ฌ์šฉ
DATETIME, DATE, TIME ๋‚ ์งœ์™€ ์‹œ๊ฐ„  

 

3. MySQL์˜ ์ปฌ๋Ÿผ ์˜ต์…˜์„ ์ฑ„์šฐ์‹œ์˜ค.

์˜ต์…˜ ๋น„๊ณ 
PRIMARY KEY (PR) ๊ธฐ๋ณธํ‚ค
NULL, NOT NULL (NN) NULL ํ—ˆ์šฉ ์—ฌ๋ถ€
UNIQUE INDEX (UQ) ๊ณ ์œ ๊ฐ’
BINARY (B) ๋ฐ์ดํ„ฐ๋ฅผ ์ด์ง„ ๋ฌธ์ž์—ด๋กœ ์ €์žฅ
UNSIGNED (UN) ์Œ์ˆ˜๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ˆซ์ž ์ €์žฅ,
FLOAT์™€ DOUBLE์—๋Š” ์ ์šฉ ๋ถˆ๊ฐ€๋Šฅ
ZEROFILL (ZF) ์ˆซ์ž์˜ ์ž๋ฆฟ์ˆ˜๋ฅผ ๊ณ ์ •
INT(4)์— 1 ์ €์žฅ → 0001
AUTO_INCREMENT (AI) ์ˆซ์ž๋ฅผ ์ž๋™์œผ๋กœ ์ฆ๊ฐ€
GENERATED COLUMN (G) ๋‹ค๋ฅธ ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์ˆ˜์‹์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฐ’

 

4. ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„๊ฐ€ 1:N์ผ ๋•Œ, 1์ธ ๋ชจ๋ธ์€ (hasMany) ๋ฉ”์„œ๋“œ๋กœ, N์ธ ๋ชจ๋ธ์€ (belongsTo) ๋ฉ”์„œ๋“œ๋กœ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.

5. ๋…ธ๋“œ์—์„œ MySQL ์ž‘์—…์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ (์‹œํ€„๋ผ์ด์ €)๋ผ๊ณ  ํ•œ๋‹ค.

6. ๋ชจ๋ธ์„ ์ •์˜ํ•  ๋•Œ, ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์„ค์ •์€ (static initiate) ๋ฉ”์„œ๋“œ๋ฅผ, ๋‹ค๋ฅธ ๋ชจ๋ธ๊ณผ์˜ ๊ด€๊ณ„ ์ž‘์„ฑ์€ (static associate) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

์ฝ”๋“œ ๋ฌธ์ œ

1. ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์„ธ์š”.

const Sequelize = require('sequelize');

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};

const sequelize = new Sequelize(config.{1๋ฒˆ ๋นˆ์นธ}, config.{2๋ฒˆ ๋นˆ์นธ}, config.{3๋ฒˆ ๋นˆ์นธ}, config);
db.sequelize = sequelize;

module.exports = db;

์ •๋‹ต: database, username, password

 

2. ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์„ธ์š”.

const Sequelize = require('sequelize');

class Comment extends Sequelize.Model {
  static {1๋ฒˆ ๋นˆ์นธ}(sequelize) {
    Comment.init({
      comment: {
        type: Sequelize.STRING(100),
        allowNull: false,
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: true,
        defaultValue: Sequelize.NOW,
      },
    }, {
      ...
  }

  static {2๋ฒˆ ๋นˆ์นธ} (db) {
    db.Comment.{3๋ฒˆ ๋นˆ์นธ}(db.User, { foreignKey: 'commenter', targetKey: 'id' });
  }
};

module.exports = Comment;

์ •๋‹ต: initiate, associate, belongsTo

 


Node.js #2 

Editor : ํŒŒ์˜ค๋ฆฌ

728x90

๊ด€๋ จ๊ธ€ ๋”๋ณด๊ธฐ