[데이터베이스] MVC Cmarket Database - Models(1)

윤후·2022년 3월 13일
0

Section 3

목록 보기
27/41

Sprint풀이


models/index.js

const db = require('../db');

module.exports = {
  items: {
    get: (callback) => {
      // TODO: Cmarket의 모든 상품을 가져오는 함수를 작성하세요
      const queryString = `SELECT * FROM items`;

      db.query(queryString, (error, result) => {
        callback(error, result);
      });
    },
  },
  orders: {
    get: (userId, callback) => {
      // TODO: 해당 유저가 작성한 모든 주문을 가져오는 함수를 작성하세요
      const queryString = `SELECT orders.id, orders.total_price, orders.created_at, items.name, items.price, items.image, order_items.order_quantity 
      FROM orders
      JOIN order_items ON orders.id=order_items.order_id
      JOIN items ON order_items.item_id=items.id
      WHERE orders.user_id=?`

      db.query(queryString, [userId],(error, result) => {
        callback(error, result);
      })
      
    },
    post: (userId, orders, totalPrice, callback) => {

      const queryString = `INSERT INTO orders (user_id, total_price) VALUES (?, ?)`
      const  QueryResult = function(something) { db.query(queryString, [userId, totalPrice], (error, result) =>{  
      return something(error, result)
      })}

      console.log(orders)
      // [ { quantity: 1, itemId: 5 }, { quantity: 1, itemId: 4 } ]

     

      return QueryResult((error, result) => {
        const querySt =  `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES
        console.log(result.insertId)
        let ordersMapping = orders.map((item) => {
          return [result.insertId, item.itemId, item.quantity]
        })
        console.log(ordersMapping)
        return db.query(querySt, [ordersMapping], (error, result) => {

	         return callback(error, result);
        })
      })

    }
  },
};

models는 이번 sprint에서 가장 어렵고 꽃과 같은 부분이었다.
npm test의 내용에서도 post를 먼저 채우고 get부분을 채우라고 한다. 이유는, 데이터베이스를 확인하면 답이나온다. 아직 아무런 값이 들어가지 않았기 때문이다.

그렇다면 왜 아직 아무런 값이 들어가지 않았을까? 어떤 테이블이 들어가있는지 있는지 확인하기 위하여 schema.sql파일을 확인하여 테이블의 구조가 어떻게 되어 있는지를 먼저 확인해 보았다.

schema.sql

CREATE TABLE users (
  id INT AUTO_INCREMENT,
  username varchar(255),
  PRIMARY KEY (id)
);

CREATE TABLE items (
  id INT AUTO_INCREMENT,
  name varchar(255),
  price INT,
  image varchar(255),
  PRIMARY KEY (id)
);

CREATE TABLE orders (
  id INT AUTO_INCREMENT,
  user_id INT,
  total_price INT,
  created_at datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

CREATE TABLE order_items (
  id INT AUTO_INCREMENT,
  order_id INT,
  item_id INT,
  order_quantity INT,
  PRIMARY KEY (id)
);

ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users (id);

ALTER TABLE order_items ADD FOREIGN KEY (order_id) REFERENCES orders (id);

ALTER TABLE order_items ADD FOREIGN KEY (item_id) REFERENCES items (id);

/*  Execute this file from the command line by typing:
 *    mysql -u root < server/schema.sql -p -Dcmarket
 *  to create the database and the tables.*/

테이블을 위와 같이 만들어져 있는 것을 볼 수 있겠다. 해당 sql파일을 더욱 시각화 하기 위해서 아래와 같은 작업을 해보았다.

참조
schema Design

이제 다시 models/index.js의 파일로 돌아가 post를 먼저 수행해보자. get의 요청은 위의 스키마로 연결하여 SELECT, JOIN, 등을 수행하여 데이터를 전해주는 역할을 한다. post는 INSERT INTO로 JOIN을 수행하기 전의 상태의 테이블에 값을 저장하는 역할이다.

다시 말하자면, post의 역할을 수행하여 테이블에 값을 추가하고 get으로 select, join을 사용하여 테이블을 합친 이 데이터를 다시 유저에게 보내는 것이다.

post부분을 채워보자.

post: (userId, orders, totalPrice, callback) => {

      const queryString = `INSERT INTO orders (user_id, total_price) VALUES (?, ?)`
      
			const  QueryResult = function(something) { db.query(queryString, [userId, totalPrice], (error, result) =>{
        return something(error, result)
      })}

      console.log(orders)
      // [ { quantity: 1, itemId: 5 }, { quantity: 1, itemId: 4 } ]

     

      return QueryResult((error, result) => {
        const querySt =  `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`

        console.log(result.insertId)

        let ordersMapping = orders.map((item) => {
          return [result.insertId, item.itemId, item.quantity]
        })

        console.log(ordersMapping)

        return db.query(querySt, [ordersMapping], (error, result) => {

          return callback(error, result);
        })
      })

위와 같은 코드를 쓰기전에 먼저 query를 어떻게 사용되고 있는지를 살펴봐야 한다.

참조
Node.js로 db다루기

위의 페이지에는 CRUD의 기본적인 명령어들이 있지만 우리가 여기서 필요한것은 INSERT부분이니 간략하게 가져와 보자.

var sql = 'INSERT INTO topic (title, description, author) VALUES("Express", "Web framework", "jacob")';

conn.query(sql, function(err, result, fields){
    if(err) console.log(err);
    console.log(rows.insertId); // insertId는 auto_increment설정해 놓았다.(고유한 식별자를 알아낼 수 있는 방법이다.)
});
//sql문을 하드코딩 하지 않고, ? 라는 치환자를 두어 코딩함
var sql = 'INSERT INTO topic (title, description, author) VALUES(?, ?, ?)';

var params = ['Supervisor', 'Watcher', 'graphittie'];//파라미터를 값들로 줌(배열로 생성)

conn.query(sql, params, function(err, result, fields){// 쿼리문 두번째 인자로 파라미터로 전달함(값들을 치환시켜서 실행함. 보안과도 밀접한 관계가 있음(sql injection attack))
    if(err) console.log(err);
    console.log(rows.insertId);
});

위와 아래의 코드를 살펴보자. 가장 큰 차이점은 VALUES에 (?, ?, ?)가 있다는 점이다.

사실 테이블에 INSERT INTO로 테이블을 삽입하고, 값을 삽입할 때, 테이블에 들어가는 값의 수가 적으면 위의 코드처럼 하나하나 하드코딩으로 값을 넣을 수 있다. 다만, 어떤 값이 들어올지 모른다거나, 수만가지의 값이 들어온다면 어떻게 해야할까?

위의 코드처럼 값을 사람이 하나씩 모두 넣는다는 것은 엄청난 비효율을 발생시킬 것이다. 하여 아래 코드와 같은 방법을 고안한 것이다.

query(sql, params, function(err, result, fields))
  • sql : sql문이 들어가는 자리이다. 해당 예시에는 INSERT INTO가 사용 되었고, VALUES는 여러 값을 넣기 위해서 (?, ?, ?)를 사용하였다.
  • params : VALUES의 값이 들어가기 위한 배열이다. 해당 예시에 table은 title, description, author 3가지가 들어가게 되는데, 이에 해당하는 값은 params의 배열인 Supervisor, Watcher, graphittie 이 순서대로 들어가게 되는 것이다.
  • function : query문을 실행한 결과를 콜백함수로 받게 된다.
    • err : 에러가 발생하여 결과를 받지 못했거나 잘못된 코드를 받았을 경우 err로 에러를 핸들링한다.
    • result : 실행한 결과를 result 객체로 받게 된다.

위의 INSERT INTO 방식으로 query문을 날려보자.

post: (userId, orders, totalPrice, callback) => {

	const queryString = `INSERT INTO orders (user_id, total_price) VALUES (?, ?)`
   
	db.query(queryString, [userId, totalPrice], (error, result) =>{   
     return callback(error, result)
   })
}

query문을 날리기 위해서는 INSERT INTO로 어디의 테이블에 값이 추가할지를 찾아야한다. Cmarket의 페이지를 실행해보면 아이템을 선택하고 주문하기를 누르면 주문 내역에 내가 선택한 주문의 목록이 뜨게되는 것이다. 허나, 현재의 주문하기 버튼을 누르더라도 주문의 목록에는 주문이 들어가지 않는 것을 확인할 수 있다.
또한, Controllers/index.js를 보면 orders.post 부분을 보면 req.body.orders, req.body.totalPrice로 해당 주문내역과 전체 가격이 들어오는 것을 볼 수 있다.

위와 같은 관계들을 살펴볼 때, INSERT INTO로 값이 삽입 되어야 할 곳은 orders 테이블인 것이다.

-번외-
사실, post에 들어오는 orders라는 변수가 무엇을 가지고 들어오는지 몰라서 console.log를 찍어보았다.

console.log(orders)
      // [ { quantity: 1, itemId: 5 }, { quantity: 1, itemId: 4 } ]

이로써 query를 구현할 구체적인 틀이 보이기 시작한다. sql문을 먼저 작성해보자.

profile
궁금한걸 찾아보고 공부해 정리해두는 블로그입니다.

0개의 댓글

관련 채용 정보