생각기록

2022-12-06 sequelize로 방명록, 회원가입 본문

SeSAC 풀스택/Nodejs

2022-12-06 sequelize로 방명록, 회원가입

끼록관 2022. 12. 6. 19:22

 

sequelize 란?

자바스크립트 구문을 알아서 SQL로 변환해준다.

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

 

 

orm

object-relation mapping

slq문을 쓰지 않고, 자바스크립트 함수를 실행해서 sql이 알아서 실행 되도록 하는 것

이거 안써도 된다.

데이터베이스를 바꾸는 일이 별로 없지만

데이터베이스를 바꾸게 되면 sql도 바꿔야 하는데....

씨퀄라이즈 orm을 쓰게 되면 애초에 js 함수라서 연결에 데이터베이스에 맞게끔 sql문을 자동으로 날려준다.


작업에 필요한 얘들을 설치

 

npm install

pakage.json 파일에 있는 것들이 자동으로 깔린다.

저번 방명록 실습 코드에서

model 파일 빼고 그대로임

 

기존은 mysql 패키지로 접속햇다면

시퀄라이즈로 db접속


1. sequlize 설치

모듈이 총 3개 필요함

npm install sequelize sequelize-cli mysql2

> npm i sequelize mysql2

> npm i -g sequelize-cli

  • sequlize  : 시퀄라이즈 패키지
  • sequlize-cli : 시퀄라이즈 명령어 실행
  • mysql2 : mysql와 시퀄라이즈 연결하는 드라이버 도구

설치가 되면 이렇게 생긴다.

 

 

2. 데이터베이스 관련 파일 따로 만들기

config 폴더 만들기

연결할 데이터 베이스 정보 작성

config / config.json 파일 만들기

제이슨파일은 { } 형태이며 키:벨류 형태

개발, 배포 환경을 분리 가능 

변경사항이 생기면, database 관련 config json 파일 수정하면 됩니다.

 

 

3. db table 모델링 하기 : 프로젝트에서 사용할 DB table을  프로젝트/model/모델.js 생성

model 폴더의

index.js, Visitor.js 사용

 

 

model/index.js

데이터베이스에 접근하는 기능을 json 파일로 접근하고

자바스크립트 구문을 알아서 sql로 변환해주는 sequelize 모듈을 불러 옵니다.

 

4. sequlize - DB 연결

new  sequlize ( ~  ); 이 부분에 

인자의 순서가 정해져 있다.

1. DB이름 ( config에 저장 되어있음 )

2. 사용자 이름

3. 비밀번호

4. 데이터베이스 전체 정보, 호스트 정보

데이터베이스 커넥션 정보를 가지고 있는 부분이다.

 

new  sequlize ( ~  );

config.json에 있는 DB값으로 새로운 sequelize 객체를 생성하여

const db = { } 객체에 넣고, 마지막에 다른곳에서도 sequlize 객체를 사용하도록 db를 exports 하고 있다.

model.index.js 통해 시퀄라이즈와 Visitor에 접근 할 수 있다.

 

db라는 객체를 만들고

key : value 형태로

sepuelize, Sepuelize 값들을  넣어 준다.

 

 

Visitor 을 import했으니 이 파일에서 모델을 정의 한다.

4. 모델 정의

model/Visitor.js 파일

 

Sequelize.define 모델 정의

Visitor이라는 함수를 실행하면, 해당 모델을 정의하도록 설계

씨퀄라이즈를 사용하려면, 실제 데이터베이스 테이블 정보를 자바스크립트 언어로 정의해줘야 한다.

 

sequelize.define(parm1, parm2, parm3 );

  • parm1 : 모델(테이블) 이름 설정
  • parm 2 : 컬럼 정의
  • parm 3: 모델 옵션 정의 (ex 한글 인코딩..등)

sql문에서 create tabel visitor2 ( id, pw, name ) 이라한다면

Sequelize.define 정의에서는

"visitor2", { 컬럼 정의 }, { 모델 옵션 정의  }

DB visitor2가 없으면, 생성해주고 존재하면 orm 객체 모델이 된다.

칼럼은 id(프라이머리 키), createAT, updateAT을 자동 생성한다.

 

DataTypes는 

이 타입관련을 정의하는 부분이다.

sql문과 시퀄라이즈문이 좀 다르기 때문에 

공식문서 참고해라

대소문자 조심해라... 이것때매 오류 많이 먹었다..!!

define() 인자

컬럼 정의 부분

  • type : 데이터 타입을 정의(문자, 숫자, 날짜 등등)
  • primaryKey : 기본 키 설정(default : false) 시퀄 라이즈에서는 기본적으로 primaryKey 컬럼을 생성한다.(id라는 이름으로 생성)
  • autoIncrement : 숫자 자동 증가(default : false)
  • allowNull : NOT NULL 허용 여부(default : true)
  • unique : Unigue 조건인지 아닌지에 대한 옵션
  • comment : column에 대한 설명 작성 가능
  • validate : 데이터 유효성 검사를 하는 속성

참고

https://any-ting.tistory.com/50

allowNull : false => null 허용하지 않는다.

primarykey : true => 기본값이 false여서 true로 해줘야 한다.

 

 

 

모델 옵션 부분

tablename : 말그대로 테이블 명

시퀄라이즈는 기본적으로 테이블을 복수형으로 만드려고 한다.

//select * from visitor; > 자동으로 visitors라고 만든다.

 

그래서 여기에 영향 받지 않겟다고

freezeTableName : true; > 얼리겠다.

 

timestamps : false 

기본값 true

true기준 > 데이터 row가 생성될때마다 생성시간, 수정시간이 계속 찍고 저장하려고 든다.
                 creatAt modifyAt 컬럼에 저장하려고 듬 (필요하면 컬럼 만들어두고 true 하면 됩니다.)
                  collate, charset : 테이블 한글 인코딩 / but 나는 데이터베이스 자체에 한글베이스 해놔서 다들 자동 한글 가능

 

 

이렇게 정의된 함수를

model/index.js 파일에서

require('./Visitor')불러오는 동시에 ( sequlize, Sequlize ) 로 실행 시키고 있다.

 

https://alencion.tistory.com/48

 

[Nodejs] Sequelize로 DB연결하기.

Seqeulize 사용하기seqeulize는 nodejs에서 웹을 데이터베이스에 연동할 때 사용하는 미들웨어이다. seqeulize는 DB에서 조회 된 값을 객체로 전달해주는 ORM(object-relational mapping)이다.Seqeulize 사전작업 npm에

alencion.tistory.com

참고


이어진 모델들을 받는

 

컨트롤러파일

controller/Cvisitor.js 에서

const Visitor = require("../model/Visitor");

이전에는 라고 정의해서 썼다면

 

오늘 배운 시퀄라이즈로 응용하자면

모델 index.js파일 중 db를  객체 형태로 된 exports했는데,

 

따라서 컨트롤러 파일에서도 받을 때 객체 안의 Visitor가 reutrn 한 값을 받겠다! 라는 의미다.

const { Visitor } = ( db객체 )

예시 : let a = obj.a        //오브젝트 안의 a라는 객체 

let visitor = db.visitor    //db객체 안의 visitor이라는 객체
const { Visitor } = require("../model/index");

더보기

구조 분해 할당? 을 응용 했다고 한다 ! 참고

2022.11.17 - [Nodejs] - 2022-11-17 node.js 1

 

model/index.js 파일에서

이 db객체를 내보냈고,

controller파일에서 위의파일에서 exports 한것을 가져왔다.

const { 값 } = db ;

const { Visitor } = db ;

예시 : let a = obj.a        //오브젝트 안의 a라는 객체 

let visitor = db.visitor    //db객체 안의 visitor이라는 객체

 

 

Visitor은 Visitor파일에서 모델 정의를 리턴했고, 그 값을  exports해서 내보냈고,

그 값을 index.js 에서  db.Visitor 로 받으면서 실행했다

즉, return값을 Visitor 함수  > index 에서 실행한 return값이 db 객체에 있다.

 

 

그 다음은 

라우트를 컨트롤 한다

 

sequelize 쿼리문

visitor라는 라우터 안에

Visitor.findAll() 

시퀄라이즈의 내장 함수 / SQL문의 SELECT문과 같은 기능을 한다.

프로미스 객체기 때문에, then으로 받는다.

전체 조회를 한 결과값이 result에 담겨 있다!

이 시퀄라이즈 부분을

Q. async awqit로 바꿔보면?

이거 처음 배웠는데

  • async 함수에서만 await를 쓸 수 있고
  • await는 다음 함수가 실행 될 때까지 기다렸다가! 다음이 실행되게 하는 함수

 

then에서 result[0].id는

dataValues특징은 생략이 가능하다는 점

result[0].dataValues.id 안해도 된다.

여기서 보면 result에는 테이블의 모든 값이 조회 되어있다.


 

 

검색

.findAll() 

시퀄라이즈의 내장 함수 / SQL문의 SELECT문과 같은 기능을 한다.

프로미스 객체기 때문에, then으로 받는다.

 

 

추가

.creat({ })

SQL문의 INSERT 문과 같다.

인자 안에 추가 될 값들을 객체 형태로 정의

 

 

수정

.update ({ })

수정 시킬 값들을 객체 형태로 정의

where 조건문객체 형태로 정의 하면 된다.

 

 

삭제

.destroy({ })

SQL문의 DELETE와 같다.

데이터베이스객체.삭제 where 아이디가 요청아이디인,

그 후 클라이언트에게 true로 보낸다.

 

 

그 외

attributes : [ " A" ] A만 선택 가능

Order : [ { "A" , "DESC "} ] A를 기준으로 내림차순 하겠다. ( ASC 오름차순)

limit : 1 > 갯수 1개로 제한

 

 

 

 Visitor.js  & index.js 관계

 

 

모델파일과 컨트롤러 파일 참고

더보기

Cvisitor 파일 전체

// const Visitor = require("../model/Visitor");
const { Visitor } = require("../model/index");
// db = {
//     "Sequelize" : Sequelize,
//     "sequelize" : sequelize,
//     "Visitor" :  "Visitor.js에서 리턴 받은 값"
// }에서 visitor만 가져오겟다

exports.visitor = async (req, res) => { //await는 async 함수 내에서만 가능해서 지정해줘야 한다.
    let result = await Visitor.findAll(); //await는 Visitor.findAll()실행될떄까지 기다렷다가 결과가 result에 담기면, 그다음을 실행
    res.render('visitor', {data : result});

    // Visitor.findAll() //시퀄라이즈 .findAll 함수 = 셀렉트문 실행/프로미스 객체
    // .then((result)=>{
    //     console.log(result);
    //     console.log(result[0].id); //[].dataValues가 기본이라 안해도 된다.
    //     res.render("visitor", {data: result});
    // })

    // select * from visitor ; 
    // Visitor.get_visitor(function(result){
    //     console.log(result);                 
    //     res.render("visitor", {data: result});
    // })
}

exports.register = async (req, res) => {
    let result = await Visitor.create({
        name : req.body.name,
        comment : req.body.comment
    }); //insert문은 create(인자 객체)
    console.log(result);
    res.send(String(result.id));

    // let data = {
    //     name : req.body.name,
    //     comment : req.body.comment
    // }
    // Visitor.create(data) //insert문은 create(인자 객체)
    // .then((result)=>{
    //     console.log(result);
    //     res.send(String(result.id));
    // })


    // `insert into visitor(name, comment) values('${info.name}', '${info.comment}');`//아이디는 자동생성 되니 굳이 적지 않는다. 클라이언트가 넘겨준 정보를 넣어야 하는데 
    // Visitor.register_visitor( req.body, function(id){
    //     console.log(id);
    //     res.send(String(id));
    // })
}

exports.delete = async (req, res) => {
    // mysql req.body.id에 해당하는 데이터를 delete
    // 서버 응답 res.send 
    let result = await Visitor.destroy({ //delete
        where : { id : req.body.id }
    });
    console.log(result);
    res.send(true);

    // Visitor.destroy({ //delete
    //     where : { id : req.body.id }
    // })
    // .then((result)=>{
    //     console.log(result);
    //     res.send(true);
    // })
    //`delete from visitor where ID = ${req.body.id}`;
    // Visitor.delete_visitor(req.body.id, function(){
    //     res.send(true);
    // })
}

exports.get_visitor_by_id = async (req, res) => {
    // req.query.id 에 해당하는 데이터를 조회
    // 서버 응답 > 조회한 데이터

    // let result = await Visitor.findOne({
    //     where : { id : req.query.id }
    // });
    // res.send(result);

    // select id, name, comment form visitor2;
    // select id, name, comment form visitor2 order by id DESC limit 1; 오름차순
    // attributes : [ "id", "name", "comment" ] 를 하면, 부분 조회가 가능하다.
    console.log(req.query.id);
    Visitor.findOne({//한개만 찾는다.
        attributes : [ "id", "name", "comment" ],
        where : { id : req.query.id },
        order : [["id", "DESC"]],
        limit : 1
    })
    .then((result)=>{
        console.log(result);
        res.send(result);
    })

    // Visitor.findAll({
    //     where : { ID : req.query.id },
    //     limit : 1
    // })
    // select * from visitor where ID = req.query.id; sql문 
    // Visitor.get_visitor_by_id_model(req.query.id, function(rows){
    //     res.send(rows);
    // });
}

exports.update_visitor = async (req, res) => {
    // req.body 데이터를 mysql 에 update 할 수 있도록
    // 서버의 응답 
    // 어찌 업데이트 할지 즉, set 다음 구문

    let result = await Visitor.update(
        {
            name : req.body.name,
            comment : req.body.comment
        },
        { where : { id : req.body.id } }
    );
    console.log(result);
    res.send(true);

    // let data = {
    //     name : req.body.name,
    //     comment : req.body.comment
    // }
    // Visitor.update(data, {
    //     where : { id : req.body.id }
    // })
    // .then((result)=>{
    //     console.log(result);
    //     res.send(true);
    // })

    //`update visitor set name ='${req.body.name}', comment='${req.body.comment}' where ID=${req.body.ID}`
    // Visitor.update_visitor(req.body, function(){
    //     res.send(true);
    // });
}

model/index.js

const Sequelize = require('sequelize'); //데이터베이스 적어놓은 config.json불러와야한다
const config =require('../config/config.json')['development']; //제이슨 파일이여서 확장자까지 입력, 그곳의 [키]

// config =  "development" : {
//     "host" : "localhost",
//     "database" : "ar_test",
//     "username": "user",
//     "psssword" : "0530arum",
//     "dialect" : "mysql"
// }
const db = {};
//인자 네개 1.데이터베이스 이름(config에 저장되어있다.)2.유저이름3.비밀번호4.데이터베이스 전체 정보
//딕셔너리 형태 아니고 인자임 / 지금 커넥션중임
const sequelize = new Sequelize(
    config.database,
    config.username,
    config.password,
    config
);

//키벨류 설정 해준다.
db.sequelize = sequelize;
db.Sequelize = Sequelize;

//모델에대한 정의가 끝나고 이 함수 자체를 실행시켜야 한다.
db.Visitor = require("./Visitor")(sequelize, Sequelize)
//첫번째 인자는 모델 대문자 인자가 받고 있다 => 정의시킴
//두번째 인자는 모델 호출해온것을  Visitor파일에서 받고있다 시퀄라이즈 안에 DataTypes에 받고있다.
//우리가 만든 모델이름


// db = {
//     "Sequelize" : Sequelize,
//     "sequelize" : sequelize,
//     "Visitor" :  "Visitor.js에서 리턴 받은 값"
// }

module.exports = db; //db들 exports
//나중에 index.js 를 불러오는 곳은 소문자 대문자 sequlize를 사용할 수 있다.

 Visitor.js

//이 함수가 실행되어야만 시퀄라이즈 디파인으로 모델 정의
// 이걸 리턴해서 어딘가로 저장 할 것이다. > Index.js
const Visitor = (Sequelize, DataTypes) => {
    return Sequelize.define(
        "visitor2",//creat table visitor (ID, name, comment)
        {
            id : { // ID int not null primary key auto_increment
                type : DataTypes.INTEGER,
                allowNull : false, //null을 허용 x
                primaryKey : true, //기본값이 false여서, primarkey는 아니여서 true
                autoIncrement : true
            },
            name : { // name varchar(10) not null
                type : DataTypes.STRING(10),
                allowNull : false
            },
            comment: { // comment mediumtext
                type : DataTypes.TEXT('medium') //null...
            }
        },
        {
            tablename : "visitor2", //select * from visitor; > 자동으로 visitors라고 만든다.
            //기본적으로 sql만들때 테이블을 복수형으로 만드려고한다. 그래서 테이블네임을 얼리겠다라는 의미
            freezeTableName : true, //복수형태가 아닌 그대로 사용하겠다는 의미
            timestamps : false //기본값 true false라고 하지 않으면, 데이터 row가 생성될때마다 생성시간, 수정시간이 계속 찍고 저장하려고 든다.
            //creatAt modifyAt 컬럼에 저장하려고 듬 (필요하면 컬럼 만들어두고 true 하면 됩니다.)
            // collate, charset : 테이블 한글 인코딩 /but 데이터베이스 자체에 한글베이스 해놔서 다들 자동 한글 가능
    
        }
    )
}
//씨퀄라이즈를 사용하려면, 실제 데이터베이스 테이블 정보를 자바스크립트 언어로 정의해줘야 한다.

module.exports = Visitor;

 

 

 

그 외 몰랐던 얘들

 

전역변수 때매 또 헷갈렸다..

전체에서 쓸수 있는 전역 변수는

순서에 상관없이

어디에서든 어떤 기능, 값을 줫다면 그 것을 다른 곳에서도 쓸 수 있다.

ejs문의 파일이 어디서 동작하는지 기억해라

라우트 컨트롤러 파일에

Visitor.ejs를 랜더하고 있는 곳에 보면, 모든 값들을 result에 넣고,

res.render 해당 파일을 랜더하면서 이 result값을 data 키로 넘기고 있다.

ejs문에서는 data키로 값을 받고 있고,

ejs문에서는 딱히 뭔가 하는게 아니라 그저 페이지에 정보들이 출력되도록 하는 것임