코드스테이츠/코드스테이츠 @ 개발 일지

[코드 스테이츠] 92일차, "ORM" - 이후 평일 블로깅 스타일 바뀝니다.

Je-chan 2021. 10. 19. 00:19

 

  Section 3 의 특성을 고려하여 앞으로 진행을 조금 바꾼다. 원래는 기술 블로깅을 주말에 몰아서 하는 것으로 복습 블로깅을 끝내려고 했지만 지금부터는 오늘 한 스프린트들을 정리하면서 그 날 사용한 코드를 적고 주말에도 아직 이해가 되지 않는 것은 한 번 더 적는 것으로 하고자 한다. 그 이유는 첫 번째로, Section 3의 경우 배우는 것보다는 그날 배운 개념을 스프린트에 적용하는 것이 대부분이다. 그러다 보니 기술 블로깅을 할 때도 개념을 적는 것은 거의 없다. 그럴바에는 과제를 수행할 때, 내가 작성한 코드를 올리면서 그 날, 그 날 복습을 하는 것이 더 좋을 것 같다는 생각이 들었다. 두 번째로, Section 3 가 매우 어렵다. 주말에 한 번 다 복습하는 건 당연히 해야 하는데, 이걸 매일 한 번씩 더 정리함으로써 복습하는 양을 늘리는 것이 더 좋을 것 같다는 생각이 들었다. 백엔드는 뭔가 개념이 제대로 잡히지 않는 것 같아서 공식문서를 여러 번 보고, 내가 작성한 코드를 또 분석해보는 방식이 더 좋을 것 같다. 

 

  단, 그냥 내가 바로 풀 수 있었던 문제가 아니라 조금 어려웠던 것들, 나중 되면 까먹을 것 같은 것들만 적기로 한다.

 

 


[ 오늘의 TODO ]

  1. 코드 스테이츠) Solo 프로그래밍
    // ORM
    // im-sprint-shortly-mvc
  2. 패스트 캠퍼스) 인강 3개 이상 듣기 // optional
  3. 스터디 그룹) 정기 모임 
  4. 생활) 물 1L 이상 마시기
  5. 생활) 1시간 이상 걷기 
    // 걸을 시간이 없다.

[ 오늘의 코드 ]

1. ORM 설정

  ORM 을 간단하게 정의한다면 SQL 과 자바 스크립트를 연결해주는 것이다. 자바 스크립트의 객체를 SQL 로 사용할 수 있도록 변환해주는 것이라 생각하면 좋을 것 같다.

1. Migration 의 의미

  과제의 테스트 케이스를 푸는데 Migration 의 의미를 파악하는 것은 그렇게까지 중요하진 않지만, ORM 에서 Migration 의 의미를 파악하는 것은 매우 중요한 것 같다.

 

npx sequelize-cli model:generate --name url --attributes url:string,title:string,visits:integer

 

  먼저 이렇게 작성을 해주면 config, migrations, models, moduels, seeders 에 변화가 생긴다. 

 

npx sequelize-cli db:migrate

  

  이걸 작성해준다면 migration 안에 있는 파일들이 차례대로 config 에서 dialect 로 지정해준 RDMBS 문법으로 변환시켜준 후에 데이터베이스에 추가가 된다. 즉, 실질적으로 파일을 이전시켜주는 것은 migration 이다. 하지만, 외래 키(forigner key) 라던가, 일대일, 일대다, 다대다의 관계를 맺는 것은 model 안에 있는 파일에서 class 내부 static 으로 지정된 associate() 안에서 지정해주면 된다. 

 

 

 

  

2. controller 구현

1) 라우팅

 

  controller 는 view 에서 받은 데이터를 Model 로 보내 원하는 데이터를 가지고 오도록 한다. 그때, view 로부터 받는 입력은 대부분의 경우 Route 다. 어떤 url 경로를 받았는지에 따라 Routes 라는 폴더에서 Routing 분기를 하고, 분기한 것 별로 controllers 에서 model 에 요청하는 내용이 달라지도록 한다. controlle

// Routing을 해주는 파일 내부
// controller 가 작성된 파일 내부를 require 해서 요청을 달리 한다.

const controller = require("../controllers/links");
const express = require("express");
const router = express.Router();

router.get("/", controller.get);
router.get("/:id", controller.withParams);
router.post("/", controller.post);

 

  

2) Model 에 요청 보내기

  이제 문제는 요청이다. 요청을 어떻게 보낼 것인지를 생각해봐야 한다.

 

https://sequelize.org/master/manual/model-querying-basics.html

 

Manual | Sequelize

Model Querying - Basics Sequelize provides various methods to assist querying your database for data. Important notice: to perform production-ready queries with Sequelize, make sure you have read the Transactions guide as well. Transactions are important t

sequelize.org

 

 

 

  해당 사이트로 가면 sequelize 에서 어떤 메소드가 SQL 의 어떤 문법으로 바뀌는 지를 설명하고 있다. 즉, 이 메소드들을 사용해서 우리가 실제로는 SQL 문으로 작성해야하는 것들을 자바스크립트로 작성해줄 수 있게 된다. 예를 들면 INSERT INTO 의 경우 create( ) 메소드를 통해서 실현할 수 있다. 즉, 데이터베이스에 어떤 내용을 추가해주고 싶다고 하면 create( ) 를 사용하여 객체를 전달해주면 된다. 일단 db 에 쿼리문을 보내는 과정 (db.query() 등) 은 비동기로 이뤄진다는 점을 유념하고 async-await 구문이다 Promise 체이닝을 해주면 된다. 공식 문서에서는 async-await 로 해주었으나 내가 작성할 때는 Promise 체이닝을 해주었다. 

 

 getUrlTitle(_url, (err, result) => {
      url
        // .findOrCreate({
        //   where: { url: _url },
        //   defaults: { title: result },
        // })
        .create({
          url: req.body.url,
          title: result,
          visits: 1,
        })
        .then((data) => {
          console.log(data);
          res.status(201).json(data);
        })
        .catch(console.log);
    });

 

  위에 findOrCreate( ) 메소드는 그 안의 where 를 통해서 그 안에 조건을 만족하는 것이 있는지를 찾아보고 없다면 default 값으로 넣는다. 그렇기 때문에 동일한 url 이 데이터베이스에 올라가는 경우를 제외시킬 수 있게 된다. 내가 처음 작성할 때는 create 로 썼는데 같은 스터디 그룹원분 덕분에 .findOrCreate 로 해줄 수 있었다. (위 코드는 post 요청이 들어왔을 때 사용하는 구문이다.)

 

  [테이블명].findAll ( ) 의 경우 SELECT * FROM [테이블명] 의 의미와 동일하다. 즉, 모든 내용을 가져오는 것이고, findOne( ) 의 경우, 가장 첫 번째 entry, 만약 괄호 안에 조건이 존재한다면 조건에 부합하는 것들 중 가장 첫 번째의 entry 만 가져오는 구문이다. update ( ) 는 데이터베이스의 내용을 수정해주는 UPDATE 문과 동일하다. 나는 위의 메소드들을 다 사용해서 해당하는 쿼리문을 보내고, .then 을 통해서 데이터를 받아온 다음(이 데이터는 우리의 쿼리로 필터링된 데이터 값이 될 것이다) 그 데이터를 다시 한 번 가공하고 res 문을 통해서 데이터를 다시 보내줬다.

 

  참고로 respond(줄여서 res) 에는 redirect 라는 메소드가 있었다. 사용하면 get 요청된 url 이 아니라 redirect 에 인자로 넣어준 곳으로 경로를 재설정해준다. 이 때, status code 는 성공할시, 302가 된다. 

 

url.findOne({ where: { id: req.params.id } }).then((data) => {
      // TODO url visit 값을 업데이트 해줘야 한다.
      data.update({ visits: data.visits + 1 });
      // TODO redirect를 하면 경로를 다시 재설정할 수 있다.
      res.status(302).redirect(data.url);
    });