[포스코 x 코딩온] 웹 풀스택 6주차 회고 -2

sima·2023년 8월 13일
0

KDT web-8

목록 보기
7/17
post-thumbnail

Node에서 MySQL 연결

npm install mysql로 설치

model에서 connection

import mysql from 'mysql';

const conn = mysql.createConnection({
	host : 'localhost',  //DB가 설치된 호스트 IP주소
    user : 'user',       //DB 접속 유저이름
    password : '1234',   // 비밀번호
    database : 'kdt',    //DB 이름
});

-> 외부에서 최상위 root 계정에서 접근을 허용하지 않아 새로운 계정을 만들고 접근해야 함.

MySQL 사용자 추가

//사용자 추가
CREATE USER 'user'@'%' IDENTIFIED BY '비밀번호';

//권한 부여
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;

//캐시 지우고 새로운 설정 적용
FLUSH PRIVILEGES;

//비밀번호 변경
ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '비밀번호';

model에서 데이터 접근 후 controller로 view에 데이터 전달

//model/Visitor.js

export const getVisitors =(cb)=> {
	conn.query('SELECT * FROM visitor', (err, rows)=> {
    	if(err) {
        throw err;
        }
        
        console.log(rows);	//객체배열 형식으로 전달
        cb(rows);			//콜백
    };
};


//controller/visitorController.js

export const getVisitors =(req, res)=> {
	Visitor.getVisitors((result)=> {
    	res.render('visitor', {data : result}); //받은 테이터 view에 전달
    });
};

Sequelize

자바스크립트 구분을 SQL로 변환, DB작업을 쉽게 할 수 있도록 도와주는 ORM 라이브러리 중 하나
ORM(Object Relation Mapping) - 객체와 DB 테이블을 매핑시켜 관계형 데이터베이스를 객체지향적으로 사용하게 해주는 기술
ex) Node의 Sequelize, Java의 Mybatis, JPA/Hibernate

sequelize 설치
npm install sequelize sequelize-cli mysql2
sequelize - 시퀄라이즈 패키지
sequelize-cli - 시퀄라이즈 명령어 실행
mysql2 - mysql과 시퀄라이즈 연결하는 드라이버

npx sequelize init - 시퀄라이즈 사용에 필요한 폴더 생성

Sequelize 모델 정의

import {DataTypes} from "sequelize";

const classesModel =(sequelize)=> {
    const Classes = sequelize.define(
        'Classes',
        {
            id : {
                type : DataTypes.INTEGER,
                allowNull : false,
                autoIncrement : true,
                primaryKey : true
            },
            name : {
                type : DataTypes.STRING(30),
                allowNull : false,
            },
            room : {
              type : DataTypes.STRING(10),
              allowNull : true,
            },
            code : {
                type : DataTypes.STRING(10),
                allowNull : false,
            },
            professor : {
                type : DataTypes.STRING(15),
                allowNull : true,
            },
        }
    );
    return Classes;
}

export default classesModel;

이외에 컬럼 정의 시 comment, validate 속성 사용 가능

define()의 모델 옵션 정의(세번째 인자)

{
	charset : 'utf8',
    collate : 'utf8_general_ci'
    tableName : 테이블 이름 설정
    freezeTableName : true // 이름을 복수로 설정하지 않음
    timestamps : true //createdAt, updatedAt
}

Sequelize 쿼리문

findAll(), findOne() - select
create() - insert
update() - update
destroy() - delete
Seqeulize 쿼리문은 모두 Promise 반환하여 .then() 메서드 붙여 결과처리 가능

config/config.json

json형식 파일을 이용해 Sequelize, MySQL 테이블 연결

config/config.json

{
	'development' : {
      "username": "user",
      "password" :  "1234",
      "database": "kdt8",
      "host": "127.0.0.1",
      "dialect": "mysql"
    }
},
...

models/index.js

const db = {};

import Sequelize from "sequelize";
import { readFile } from 'fs/promises';
const json = JSON.parse( await readFile(new URL('../config/config.json', import.meta.url)));
const devConfig = json.development;

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

//model
import Student from "./Student.js";
import Classes from './Classes.js';
import StudentProfile from "./StudentProfile.js";

db.Student = Student(sequelize);
db.Classes = Classes(sequelize);
db.StudentProfile = StudentProfile(sequelize);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;

ES6로 작성 시 json파일을 import할 때,

import jsonFile from '../config/config.json' assert { type : json};로도 import할 순 있지만, 애플리케이션에서 해당 코드에 대해 warning으로 경고를준다. 번거롭더라도 fileSystem module을 이용해 파싱하는 방식으로 불러오는것이 안전할 것 같다.

Sequelize를 이용한 CRUD

import { default as User } from '../model/User.js';
import models from '../models/index.js';
import { Op } from 'sequelize';

const main = (req, res) => res.render('index');

const signUpGet = (req, res) => res.render('signup');

const signUpPost = (req, res) => {
    models.User.create({        //models에서 정의한 테이블 컬럼명과 대소문자 일치해야함
        userid : req.body.userId,
        pw : req.body.userPwd,
        name : req.body.userName,
    }).then((result)=> {
        console.log('result : ', result);
        res.send({ result : true });
    })
}

const signInGet = (req, res) => res.render('signin');

const signInPost = (req, res)=> {
    models.User.findOne({
        where : {
            userid : req.body.userId,
            pw : req.body.userPwd,
        },
    }).then((result)=> {
            console.log('result : ', result);
            res.render('profile', {'userInfo' : result}); // result.dataValues 생략 가능
    });
}

const editInfo = (req, res) => {
    const { userid, pw, name, id } = req.body;
    models.User.update({
       userid, pw, name         //객체 구조분해할당 적용 가능, 변수명과 컬럼명 같으면 하나로 생략가능
    }, {
        where : {
            id,
        }
    }).then((result)=> {
       console.log(result);  // result [1]
    });
}

const deleteInfo = (req, res) => {
    const { id } = req.body;
    models.User.destroy({ where : { id } }).then((result)=> {
        console.log('result : ', result);   //result 1
        res.send(true);
    })
}

const findAll = (req, res) => {
    models.User.findAll({
        //attribute : 원하는 컬럼 조회
        // attributes : ['name'],

        //where : 조건
        //Op.gt(초과), Op.gte(이상) Op.lt(미만), Op.ne(같지않은)
        //Op.or(또는), Op.in(배열 요소 중 하나), Op.notIn(배열 요소와 모두 다른) 등
        where : { id : { [Op.gte] : 4 } },
        // order : 정렬, 배열안에 배열 구조
        // order : [ [ 'id', 'DESC' ] ],
        // limit : 가져올 개수
        // limit : 1,
        // offset : n개 건너뛰기
        // offset : 1,
    }).then((result)=> {
       // console.log('result : ', result);
        res.send(result);  //배열형태로 send
    });
}

SQL JOIN

두 개 이상의 테이블에서 데이터를 결합하여 새로운 결과 생성, 테이블 간 관계를 통해 정보를 얻어내야 할 때 JOIN을 사용하여 관련 데이터를 결합하고 원하는 정보 추출

조인 종류

  • INNER JOIN - 공통된 값만 가진 행 반환
  • LEFT JOIN - 왼쪽 테이블 모든 행 포함, 오른쪽 테이블 일치하는 경우 반환
  • RIGHT JOIN - 오른쪽 테이블 모든 행 포함, 왼쪽 테이블 일치하는 경우 반환
  • FULL JOIN - 양쪽 테이블 모든 행 포함, 일치하는 경우 반환
  • CROSS JOIN - 두 테이블 가능한 모든 조합 반환

Node에서의 조인

CREATE TABLE user {
	id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    ...
    ...
};

CREATE TABLE profile {
	id INT PRIMARY KEY,
    user_id INT,
    introducd VARCHAR(100),
    FOREIGN KEY (user_id) REFERENCES user(id)
};

//model
User.hasOne(Profile, { foreignKey : 'user_id' });
Profile.belongsTo(User, { foreignKey : 'user_id' });

1:1 관계

  • hasOne() - 한 모델이 다른 모델 가리키는 1:1관계 설정
  • belongsTo() - 다른 모델이 한 모델 가리키는 1:1관계 설정

1:N 관계

  • hasMany() - 한 모델이 다른 모델과 1:N관계 설정
  • belongsTo() - 다른 모델이 한 모델 가리키는 1:N관계 설정

N:M 관계

CREATE TABLE Students {
	...
    ...
};

CREATE TABLE Teachers {
	...
   	...
};

CREATE TABLE StudentTeacherRelation {
	...
    ...
    FOREIGN KEY (StudentID) REFERENCES Students(StudentID),
    FOREIGN KEY (TeacherID) REFERENCES Teachers(TeacherID)
};

//model
Student.belongsToMany(Teacher, { through : StudentTeacherRelation });
Teacher.belongsToMany(Student, { through : StudentTeacherRelation });
  • belongsToMany(, {})` - N:M관계 설정

관계 설정 이후 Controller에서의 데이터 입력, 조회

export const enrollStudent = async (req, res)=> {
    try {
        const {userid, password, email, name, major, enroll} = req.body;
        const user = await db.Student.create({
            userid, password, email,
            StudentProfile : {
                name, major, enroll,
            },
            //include : 쿼리 실행할 때 관련된 모델 데이터도 함께 조회
        }, { include : db.StudentProfile },
        );
        console.log(user);
    } catch(error) {
        console.log(error);
    }
}

export const enrollClass = async (req, res)=> {
    try {
        const { name, room, code, professor, StudentId } = req.body;
        const classes = await db.Classes.create({
            name, room, code, professor, StudentId
        })
    } catch (error) {

    }
}

export const getStudent = async (req, res) => {
  try {
    const student = await db.Student.findAll({
        attributes : ['userid', 'email'],
        include : [{ model : db.StudentProfile,
                            attributes : ['major', 'enroll']
                    }],
    });
    res.send(student);
  }  catch (error) {
      console.log(error);
  }
};

0개의 댓글