MVC- cmarket sprint (복습)

Creating the dots·2021년 10월 15일
0

SQL

목록 보기
6/21

app.js

const express = require("express");
const indexRouter = require("./routes");
const cors = require("cors");
const morgan = require("morgan");
const app = express();
const port = 4000;

app.use(morgan("      :method :url :status :res[content-length] - :response-time ms"));
app.use(cors());
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use("/", indexRouter); // 첫번째 분기점으로 /로 시작할 경우 indexRouter에 따라 분기지점이 세분화됨.

module.exports = app.listen(port, () => {
  console.log(`Server is starting on ${port}`);
});

routes/index.js

const express = require("express");
const router = express.Router();
const itemsRouter = require("./items");
const usersRouter = require("./users");

router.use("/items", itemsRouter);
router.use("/users", usersRouter);
module.exports= router;

routes/items.js

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

router.get("/", controller.items.get);
module.exports = router;

routes/users.js

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

router.get("/:userId/orders", controllers.orders.get);
router.post("/:userId/orders", controllers.orders.post);
module.exports= router;

라우팅

모든 라우터는 server/routes/index.js를 진입점으로 여기고, 여기서 endpoint에 따라 다시 분기된다.
index.js에서 /items일때, /users일때로 분기를 나눠주고 있고, items.js에서는 get 요청이 있을때 controller.items.get 메소드가 실행되도록 되어있다. users.js에서는 get과 post 요청에 따라 controllers.orders.get, controllers.orders.post 메소드가 실행되도록 되어있다.


/controllers.index.js

const models = require("../models");

module.exports = {
  items: {
    get: (req, res) => {
      models.items.get((err, result) => {
        if(err){
          return res.status(500).send("Internal Server Error");
        }else{
          return res.status(200).json(result);
        }
      });
    },
  },
  
  orders: {
    get: (req, res) => {
      const userId = req.params.userId;
      if(!userId){
        return res.status(400).end();
      }
      models.orders.get(Number(userId), (err,result) => {
        if(err){
          return res.status(400).end();
        }else{
          return res.status(200).json(result);
        }
      });
    },
    
    post: (req, res) => {
      const userId = req.params.userId;
      const {orders, totalPrice} = req.body;
      if(!orders || !totalPrice){
        return res.status(400).end();
      }else{
        models.orders.post(Number(userId), orders, totalPrice, (err, result) => {
          if(err){
            return res.status(404).end();
          }else{
            return res.status(201).json(result);
          }
         )};
       }
    }
  }
} 

/models/index.js

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

module.exports = {
  items: {
    get: (callback) => {
      const sql = `SELECT * from items`
      db.query(sql, (err,result)=>{
        callback(err,result);
      })
    },
  },
  
  orders: {
    get: (userId, callback) => {
      const sql = `
	SELECT orders.id, name, image, price, total_price, order_quantity
	FROM orders
	LEFT JOIN users
	ON users.id = orders.user_id
	LEFT JOIN order_items
	ON orders.id = order_items.order_id
	LEFT JOIN items
	ON items.id = order_items.item_id
	WHERE users.id = ?
	`
      const params = [userId];
      db.query(sql, params, (err,result)=>{
        callback(err, result);
      });
    },
    
    post: (userId, orders, totalPrice, callback) => {
      //orders 테이블에 먼저 데이터를 삽입한다
      //그 다음에 order_items 테이블에 데이터를 삽입한다
      //이유는 orders의 id를 FK로 갖는 order_items.order_id를 order_items 테이블에 데이터를 삽입할때 쓸 수 있기 때문
      const sql1 = `INSERT INTO orders (user_id, total_price) VALUES (?,?)`
      const params = [userId, totalPrice];
      
      db.query(sql1, parmas, (err, result) => {
        if(err) callback(err, null);
        else{
          const sql2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`          
          const params2 = orders.map(order => {
            return [result.insertId, order.itemId, order.quantity]
          });
          return db.query(sql2, [params2], (err,result) => {
            if(err) callback(err, null);
            else{
              callback(null, result);
            }
          });
        }
      });
    }
  }
}       

models.orders.post

endpoint: /users/1/orders
userId === 1
orders === [{itemId: 1, quantity:2}, {itemId: 2, quantity:5}]
totalPrice === 79800

첫 번째 쿼리요청에서는 orders 테이블에 데이터를 삽입하고 에러가 발생하지 않을 경우, 다음 쿼리요청이 진행된다. (orders 테이블에는 데이터가 삽입된 상태)

두번째 쿼리 요청에서는 order_items 테이블에 데이터를 삽입한다. 이때, 2개의 데이터가 삽입된다. 이것을 bulk insert라고 한다.

bulk insert를 할때

  • 쿼리문(sql2)에 ?는 하나만 작성한다.
    기존에 하나의 데이터만 삽입할 때에는 INSERT INTO (fields) VALUES (?,?,...?)로 필드 개수만큼 물음표를 작성했다. 하지만, 여러개의 데이터를 한번에 삽입할 때에는 삼중배열의 형태이기 때문에 물음표를 하나만 작성한다.

  • 쿼리요청의 두번째 인자로 전달되는 params는 삼중배열의 형태로 작성한다.
    orders는 객체들을 요소로 갖는 배열이다. map 메소드로 각 객체에 저장된 정보를 요소로 갖는 배열을 리턴시켜주었다. 그 결과 배열 안에 배열들이 있는 이중배열의 형태가 되었고, 쿼리요청의 두번째 인자로 한번더 배열로 감싸주어 삼중배열의 형태로 만든다.

  • result.insertId
    INSERT INTO 요청을 보냈을때, 데이터베이스에서 보내는 result 객체에는 여러 정보가 담겨있는데 그중 insertId는 삽입된 테이블의 pk에 해당하는 id값이다. 따라서 첫번째 쿼리문인 INSERT INTO를 성공했을때 전달받은 result 객체의 insertId를 두번째 쿼리문에서는 orders.id 대신 사용할 수 있다.

profile
어제보다 나은 오늘을 만드는 중

0개의 댓글