2023.05.19 SEQUELIZE 세팅

이무헌·2023년 7월 21일
0

mySQL

목록 보기
3/3
post-thumbnail

1.sequelize 란?

⇒sql을 편리하게 js에서 사용할 수 있도록 만들어주는 라이브러리다.
기존에 SQL문으로 query 를 써서 보내는 방식이 아닌 js문법으로 sql을 조작 할 수 있다.

💡 Sequelize는 Node.js용 ORM(Object-Relational Mapping) 라이브러리입니다. JavaScript를 사용하여 MySQL, PostgreSQL, SQLite 등과 같은 관계형 데이터베이스와 상호 작용하는 방법을 제공합니다. Sequelize는 데이터베이스 작업을 단순화하고 보다 객체 지향적인 방식으로 데이터베이스 모델, 쿼리 및 트랜잭션 작업을 보다 쉽게 수행할 수 있도록 하는 일련의 메서드 및 기능을 제공합니다. 데이터베이스 연결을 관리하고, 모델을 정의하고, 데이터베이스 테이블에서 CRUD(만들기, 읽기, 업데이트, 삭제) 작업을 수행하기 위한 강력하고 유연한 도구를 제공합니다 출처:chatGPT

2.사용해보자

  • app.js
    // 시퀄라이즈 ORM (객체관계 매핑)
    // 객체와 데이터 베이스를 ORM 라이브러리가 매핑을 시켜주어서 자바스크립트 구문으로 SQL을 제어할 수 있다.
    // 자바스크립트로만 sql작업을 할 수 있도록 도와주는 라이브러리
    
    const e = require("express");
    const path = require("path");
    const dot = require("dotenv").config();
    const { sequelize, User, Post } = require("./models");
    
    // 설치할 모듈은 express,ejs,sequelize mysql2
    // 서버 객체 만들고
    // 등등
    const app = e();
    
    app.set("views", path.join(__dirname, "page"));
    app.set("view engine", "ejs");
    app.use(e.urlencoded({ extended: false }));
    
    // 시퀄라이즈 구성 연결 매핑
    // sync함수는 데이터베이스를 동기화 시켜주는 메서드
    // true일때는 초기화가 된다.
    // false 일때는 초기화 안됨
    sequelize
      .sync({ focus: false })
      .then(() => {
        // 연결 성공
        console.log("연결 성공");
      })
      .catch((err) => {
        console.log(err);
        // 연결실패
      });
    
    app.get("/", (req, res) => {
      res.render("create");
    });
    
    app.post("/create", (req, res) => {
      const { name, age, msg } = req.body;
      // create insert 문을 실행 시켜주는 메서드
      // 매개변수로 컬럼의 내용을 객체로 만들어서 전달
      User.create({
        // name 컬럼의 값
        name: name,
        // age 컬럼의 값
        age: age,
        // msg 컬럼의 값
        message: msg,
      })
        .then(() => {})
        .catch((err) => {
          console.log("app create", err);
        });
      res.send("값 추가");
    });
    
    app.get("/main", (req, res) => {
      // findAll메서드에 매개변수로 검색 조건을 객체로 추가 할 수 있다.
      User.findAll()
        .then((e) => {
          res.render("main", { data: e });
        })
        .catch((err) => {
          console.log(err);
        });
    });
    
    app.post("/create_post", (req, res) => {
      const { name, value } = req.body;
      console.log(name, value);
    
      // 한개의 값을 조회 메서드
      User.findOne({
        // 검색 조건 추가
        where: { name: name },
      }).then((e) => {
        Post.create({
          msg: value,
          user_id: e.id,
        });
      });
      res.send();
    });
    
    app.get("/view/:name", (req, res) => {
      // 유저를 조회하고 가지고 있는 글을 볼거임
      User.findOne({
        where: { name: req.params.name },
        // 관계형으로 불러온 값을 다 풀어서 볼수가 있다.
        // raw:true,
        // 해당 유저의 id로 참조된 user_id가 있는 post테이블의 값을 같이 조회한다.
        include: [
          // 조회할 모듈 post 모델
          { model: Post },
        ],
      }).then((e) => {
        e.dataValues.Posts = e.dataValues.Posts.map((a) => {
          return a.dataValues;
        });
        const Posts = e.dataValues;
        console.log(Posts);
        res.render("view", { data: Posts });
      });
    });
    
    app.listen(8080, (req, res) => {
      console.log("성공했구나 이녀석");
    });
    • sequelize 연결하는 코드
      sequelize
        .sync({ focus: false })
        .then(() => {
          // 연결 성공
          console.log("연결 성공");
        })
        .catch((err) => {
          console.log(err);
          // 연결실패
        });
      • sequelize를 데이터베이스에 연결시켜주는 코드다
      • 구성 매핑으로 focus와 같은 옵션을 설정할 수 있다.
    • create post 요청시 테이블에 새로운 값을 넣는(insert)코드
      app.post("/create", (req, res) => {
        const { name, age, msg } = req.body;
        // create insert 문을 실행 시켜주는 메서드
        // 매개변수로 컬럼의 내용을 객체로 만들어서 전달
        User.create({
          // name 컬럼의 값
          name: name,
          // age 컬럼의 값
          age: age,
          // msg 컬럼의 값
          message: msg,
        })
          .then(() => {})
          .catch((err) => {
            console.log("app create", err);
          });
        res.send("값 추가");
      });
      • User에 있는 create(객체 생성 없이 메서드를 사용했으므로 static이다.)에
        형식에 맞게 value를 전달한다.
    • main get 요청시 모든 유저 가져오기
      app.get("/main", (req, res) => {
        // findAll메서드에 매개변수로 검색 조건을 객체로 추가 할 수 있다.
        User.findAll()
          .then((e) => {
            res.render("main", { data: e });
          })
          .catch((err) => {
            console.log(err);
          });
      });
      • findAll로 모든 데이터를 가져온 후 ejs에 보낸다.
    • 유저가 작성한 글 추가
      app.post("/create_post", (req, res) => {
        const { name, value } = req.body;
        console.log(name, value);
      
        // 한개의 값을 조회 메서드
        User.findOne({
          // 검색 조건 추가
          where: { name: name },
        }).then((e) => {
          Post.create({
            msg: value,
            user_id: e.id,
          });
        });
        res.send();
      });
      • findOne으로 조건을 추가해 한명의 유저만 가져온다.
      • 그 후 Post.create로 테이블에 새로운 값을 추가한다.
    • 유저가 작성한 글을 보는 view/:name get
      app.get("/view/:name", (req, res) => {
        // 유저를 조회하고 가지고 있는 글을 볼거임
        User.findOne({
          where: { name: req.params.name },
          // 관계형으로 불러온 값을 다 풀어서 볼수가 있다.
          // raw:true,
          // 해당 유저의 id로 참조된 user_id가 있는 post테이블의 값을 같이 조회한다.
          include: [
            // 조회할 모듈 post 모델
            { model: Post },
          ],
        }).then((e) => {
          e.dataValues.Posts = e.dataValues.Posts.map((a) => {
            return a.dataValues;
          });
          const Posts = e.dataValues;
          console.log(Posts);
          res.render("view", { data: Posts });
        });
      });
      • params로 가져온 name을 이용해 해당 행을 찾는다.
      • 그 후 해당 행의 id를 찾고, Post가 갖고있는 tableName을 조회한다.
      • 조회해서 나온 table에 외래키중에 id와 일치한(여기선 user_id)것을 찾아 갖고온다.
      • 즉, 기존 SQL에서 join on where과 비슷하다.
      • 그렇게 해선 나온 값 (e)의 dataValues안에는 찾은 값이 있는데, 우리는 Post를 조회했으므로 Posts가 있다.
      • 이 Posts의 datavalues 값 하나하나를 map으로 다시 Posts객체에 넣는다.
      • 즉, Posts는 해당 유저가 n개의 글을 썼다면 n개 만큼의 value를 갖고있지만, 우리가 원하는 건 그 value안의 datavalues뿐이므로 datavalues만을 뽑아 Posts에 재 할당해준것이다
  • models/config
    const config = {
      dev: {
        username: process.env.USERNAME,
        password: process.env.PASSWORD,
        database: process.env.DATABASE,
        host: process.env.HOST,
        dialect: "mysql",
      },
    };
    
    module.exports = config;
    • 환경변수에 설정한 값을 갖고온다.
    • dialect는 사용할 database 관리 시스템의 이름이다.
  • models/index
    const Sequelize = require("sequelize");
    const config = require("./config");
    const User = require("./users");
    const Post = require("./post");
    
    // 시퀄라이즈 객체 생성
    const _sequelize = new Sequelize(
      config.dev.database,
      config.dev.username,
      config.dev.password,
      config.dev
    );
    
    // 내보낼 빈 객체
    const db = {};
    db.sequelize = _sequelize;
    db.User = User;
    db.Post = Post;
    // 테이블을 초기화 하는 부분
    User.init(_sequelize);
    Post.init(_sequelize);
    console.log('asd')
    User.associate(db)
    Post.associate(db)
    module.exports = db;
    • _sequelize 객체를 생성한다.
    • 당연히 동적으로 생성해야한다.
    • db라는 빈 객체에 넣고 한번에 module을 내보낸다.
    • init과 associate은 뒤에 설명한다.
  • models/post
    const Sequelize = require("sequelize");
    
    class Post extends Sequelize.Model {
      static init(sequelize) {
        return super.init(
          {
            msg: { type: Sequelize.STRING(100), allowNull: false },
          },
          {
            sequelize,
            timestamps: true,
            modelName: "Post",
            tableName: "posts",
            charset: "utf8",
            collate: "utf8_general_ci",
          }
        );
      }
      static associate(db) {
        // 1:N 예
        // 1:N 관계
        // 시퀄라이즈에서 1:N관계를 hasMany 메서드로 정의해준다.
        // sourceKey: user테이블 안에 어떤키를 foreignKey와 연결해줄지.
        // hasMany 메서드의 첫번째 매개변수 넘긴 테이블이 foreignKey에 연결이되고 이름은 user_id다.
    
        // belongsTo 메서드를 사용해서 user에 id를 foreignKey로 연결한다.
        // 유저의 id가 따라갈 키 참조키는 user_id
    
        db.Post.belongsTo(db.User, { foreignKey: "user_id", targetKey: "id" });
      }
    }
    
    module.exports = Post;
    • 클래스 Post를 만들고 Sequelize를 상속한다.
    • 전역 함수 init을 만들고 return으로 super(부모. 즉 Sequelize에 있는 함수) 의 init을 준다.
    • init은 sql에서 createTable과 같다
    • associate는 외래키와 테이블간의 관계를 표현한다. 여기선 유저 한명이 여러 포스트를 가질 수 있으므로 1:N관계에서 N이다.
    • belongsTo 로 첫번째 매개변수로 User를 참조하고 외래키는 생성한 user_id로 준다. 그 후 타겟시킬(targetKey) user의 칼럼값은 id로 한다.
  • models/users
    const Sequelize = require("sequelize");
    
    // user 클래스에 시퀄리아즈 안의 model 클래스를 상속 시켜준다.
    class User extends Sequelize.Model {
      static init(sequelize) {
        // super 상속받은 부모의 함수를 실행 init 실행시켜서 반환
        // init 메서드는 첫번쨰 매개변수로 컬럼에 대한 설정값이 들어가고
        // 두번째 매개변수로 테이블의 자체 설정 값이 들어간다.
        return super.init(
          {
            // 컬럼에 대한 설정
            // name 컬럼
            // VARCHAR => STRING으로
            // allowNull:null을 혀용할지
            // unique:고유키로 사용할 것인지 중복되지 않는 값.
            // primaryKey:프라이머리키 설정
            name: {
              type: Sequelize.STRING(20),
              allowNull: false,
              unique: true,
              primaryKey: false,
            },
            age: {
              type: Sequelize.INTEGER,
              allowNull: false,
            },
            // TEXT = TEXT
            message: {
              type: Sequelize.TEXT,
            },
          },
          {
            // 테이블의 자체 설정
            // 매개변수로 전달받은 _squelize먼저 작성해주고
            sequelize,
            //테이블에 row 추가 했을 때 생성시간과 업데이트 시간을 표기 해준다.
            // created_at과 updated_at 이라는 컬럼이 자동으로 추가된다.
            // 우리가 row추가했을 때 시간을 기록, 수정했을 때도 시간을 기록해준다.
            timestamps: true,
            // 표기법을 바꿔준다. 기본적으로 스네이크 표기법으로 되어있는데,
            // 이를 카멜 표기법으로 바꿔준다.
            underscored: false,
            modelName: "User", //모듈의 이름을 설정. 노드 프로젝트에서 사용
            tableName: "users4", //복수형으로 설정해주자. 추가될 테이블의 이름
            paranoid: false, //true로 설정하면 delete_at이라는 컬럼도 생성이 됩니다. 이는 값은 삭제되지않고 남아있고, deleted_at에 삭제시간이 표시됨
            charset: "utf8", //인코딩 방식, 꼭 작성하자
            collate: "utf8_general_ci", //인코딩 방식 꼭 작성하자
          }
        );
      }
      static associate(db) {
        // 1:N 예
    
        // 1:N 관계
        // 시퀄라이즈에서 1:N관계를 hasMany 메서드로 정의해준다.
        // sourceKey: user테이블 안에 어떤키를 foreignKey와 연결해줄지.
        // hasMany 메서드의 첫번째 매개변수 넘긴 테이블이 foreignKey에 연결이되고 이름은 user_id다.
        db.User.hasMany(db.Post, { foreignKey: "user_id", sourceKey: "id" });
      }
      
    }
    
    module.exports = User;
    • post와 마찬가지이다.
    • 여기선 1:N에서 1이므로 hasMany를 사용한다.
    • user_id를 외래키로 갖고있는 post를 참조하고 그 근원(sourceKey)은 자신의 id이다.

3.느낀점

💡 저번주부터 계속 모르는 개념이 등장하고 새로운걸 배우고 있다. 기본개념을 계속 숙지해서 그런지 따라가는데는 문제가 없지만 항상 응용을 하면 잔버그가 나온다. 대부분 단순 실수이므로 침착하게 관계를 잘 생각하고 데이터베이스를 설계하는 것이 중요한 것 같다. 곧 배울 socket개념도 잘 숙지해서 백엔드 개발자의 밑거름을 잘 닦아야한다.
profile
개발당시에 직면한 이슈를 정리하는 곳

2개의 댓글

comment-user-thumbnail
2023년 7월 21일

유익한 글 잘 봤습니다, 감사합니다.

답글 달기
comment-user-thumbnail
2023년 7월 21일

훌륭한 글이네요. 감사합니다.

답글 달기