mongoose를 사용하여 mongoDB를 node.js에서 사용하기 4 --> delete, patch, put (api 표현들)

하이루·2021년 12월 9일
0
post-custom-banner

장바구니 기능 추가

View폴더에 있는 Cart.ejs

            <!DOCTYPE html>
            <html lang="en">
              <head>
                <!-- Required meta tags -->
                <meta charset="utf-8" />
                <meta
                  name="viewport"
                  content="width=device-width, initial-scale=1, shrink-to-fit=no"
                />
                <link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
                <link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
                <!-- Bootstrap CSS -->
                <link
                  rel="stylesheet"
                  href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
                  integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
                  crossorigin="anonymous"
                />

                <!-- Font Awesome CSS -->
                <link
                  href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
                  rel="stylesheet"
                />
                <!-- Optional JavaScript -->
                <!-- jQuery first, then Popper.js, then Bootstrap JS -->
                <script
                  src="https://code.jquery.com/jquery-3.5.1.js"
                  integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
                  crossorigin="anonymous"
                ></script>
                <script
                  src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
                  integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
                  crossorigin="anonymous"
                ></script>
                <script
                  src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"
                  integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s"
                  crossorigin="anonymous"
                ></script>
                <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>

                <link href="/static/mystyle.css" rel="stylesheet" />
                <title>스파르타 쇼핑몰 | 장바구니</title>
                <script>
                  $(document).ready(function() {
                    get_goods();
                    $("#categorySelect").on("change", function() {
                      get_goods($(this).val());
                    });
                  });

                  function sign_out() {
                    $.removeCookie("mytoken", { path: "/" });
                    $.removeCookie("userName", { path: "/" });
                    window.location.href = "/";
                  }

                  function get_goods() {
                    $("#goodsList").empty();
                    $.ajax({
                      type: "GET",
                      url: `/api/cart`,
                      data: {},
                      success: function(response) {
                        let goods = response["cart"];
                        for (let i = 0; i < goods.length; i++) {
                          make_card(goods[i]["goods"]);
                        }
                        getSum();
                      }
                    });
                  }

                  function order() {
                    $.ajax({
                      type: "GET",
                      url: `/api/cart`,
                      data: {},
                      success: function(response) {
                        let goods = response["cart"];
                        let cart = [];
                        for (let i = 0; i < goods.length; i++) {
                          cart.push({
                            goodsName: goods[i]["name"],
                            quantity: goods[i]["goodsId"]
                          });
                        }
                        sessionStorage.setItem("cart", JSON.stringify(cart));
                        window.location.href = "/order";
                      }
                    });
                  }

                  function make_card(item) {
                    let htmlTemp = `<div class="card mb-2">
                                                <div class="row no-gutters">
                                                    <div class="col-4" style="background: #868e96;"token interpolation">${
                                                      item["goodsId"]
                                                    }'">
                                                        <img src="${item["thumbnailUrl"]}"
                                                             class="card-img-top h-100" alt="...">
                                                    </div>
                                                    <div class="col-8">
                                                        <div class="card-body py-1">
                                                            <div class="card-title row mt-2">
                                                                <p class="font-weight-bold col" style="display: inline">${
                                                                  item["name"]
                                                                }</p>
                                                                <span class="card-price col text-right">$${number2decimals(
                                                                  item["price"]
                                                                )}</span>

                                                            </div>
                                                            <div class="form-group row mr-0">
                                                                <div class="col-7 pr-2">
                                                                    <button class="btn btn-outline-sparta btn-block"token interpolation">${
                                                                      item["goodsId"]
                                                                    })">삭제</button>
                                                                </div>
                                                                <select class="custom-select col-5" id="numberSelect-${
                                                                  item["goodsId"]
                                                                }">
                                                                    <option selected value=1>1</option>
                                                                    <option value=2>2</option>
                                                                    <option value=3>3</option>
                                                                </select>
                                                            </div>

                                                        </div>


                                                    </div>
                                                </div>
                                            </div>`;
                    $("#goodsList").append(htmlTemp);
                    $(`#numberSelect-${item["goodsId"]}`).change(function() {
                      // console.log(parseInt($(this).val()))
                      $.ajax({
                        type: "PATCH",
                        url: `/api/goods/${item["goodsId"]}/cart`,
                        data: {
                          quantity: parseInt($(this).val())
                        },
                        success: function(response) {
                          if (response["result"] == "success") {
                            console.log(response["msg"]);
                            getSum();
                          }
                        }
                      });
                    });
                  }

                  function removeItem(goodsId) {
                    $.ajax({
                      type: "DELETE",
                      url: `/api/goods/${goodsId}/cart`,
                      data: {},
                      success: function(response) {
                        if (response["result"] == "success") {
                          get_goods();
                        }
                      }
                    });
                  }

                  function getSum() {
                    let $prices = $(".card-price");
                    let $selects = $("select");
                    if ($prices.length != $selects.length) {
                      console.log("길이가 맞지 않습니다.");
                      return;
                    }
                    let sum = 0;
                    for (let i = 0; i < $prices.length; i++) {
                      let price = parseFloat(
                        $($prices[i])
                          .text()
                          .replace("$", "")
                      );
                      let count = parseInt($($selects[i]).val());
                      // console.log(price, count)
                      sum += price * count;
                    }
                    $("#priceSum").text("$" + number2decimals(sum));
                    sessionStorage.setItem("priceSum", number2decimals(sum));
                  }

                  function number2decimals(num) {
                    return (Math.round(num * 100) / 100).toFixed(2);
                  }
                </script>
                <style>
                  .card {
                    cursor: pointer;
                  }
                </style>
              </head>

              <body>
                <nav
                  class="navbar navbar-expand-sm navbar-dark bg-sparta justify-content-end"
                >
                  <a class="navbar-brand" href="/goods">
                    <img
                      src="/static/logo_big_tr.png"
                      width="30"
                      height="30"
                      class="d-inline-block align-top"
                      alt=""
                    />
                    스파르타 쇼핑몰
                  </a>
                  <button
                    class="navbar-toggler ml-auto"
                    type="button"
                    data-toggle="collapse"
                    data-target="#navbarSupportedContent"
                    aria-controls="navbarSupportedContent"
                    aria-expanded="true"
                    aria-label="Toggle navigation"
                  >
                    <span class="navbar-toggler-icon"></span>
                  </button>
                  <div
                    class="navbar-collapse collapse flex-grow-0 ml-auto"
                    id="navbarSupportedContent"
                    style=""
                  >
                    <ul class="navbar-nav mr-auto text-right">
                      <li class="nav-item" id="link-cart">
                        <a class="nav-link" href="/cart">
                          장바구니<i
                            class="fa fa-shopping-cart ml-2"
                            aria-hidden="true"
                          ></i>
                        </a>
                      </li>
                      <li class="nav-item" id="link-logout">
                        <a class="nav-link" data-toggle="modal" data-target="#signOutModal">
                          로그아웃<i class="fa fa-sign-out ml-2" aria-hidden="true"></i>
                        </a>
                        <div
                          class="modal text-left"
                          id="signOutModal"
                          tabindex="-1"
                          role="dialog"
                          aria-labelledby="signOutModalLabel"
                          aria-hidden="true"
                        >
                          <div class="modal-dialog" role="document">
                            <div class="modal-content">
                              <div class="modal-header">
                                <h5 class="modal-title" id="signOutModalLabel">로그아웃</h5>
                                <button
                                  type="button"
                                  class="close"
                                  data-dismiss="modal"
                                  aria-label="Close"
                                >
                                  <span aria-hidden="true">&times;</span>
                                </button>
                              </div>
                              <div class="modal-body">
                                로그아웃하시면 장바구니가 사라져요!
                              </div>
                              <div class="modal-footer">
                                <button
                                  type="button"
                                  class="btn btn-outline-sparta"
                                  data-dismiss="modal"
                                >
                                  취소
                                </button>
                                <button
                                  type="button"
                                  class="btn btn-sparta"
                                  onclick="sign_out()"
                                >
                                  로그아웃하기
                                </button>
                              </div>
                            </div>
                          </div>
                        </div>
                      </li>
                    </ul>
                  </div>
                </nav>
                <div class="wrap">
                  <div class="mb-3">
                    <h4>
                      <i class="fa fa-shopping-cart mr-1" aria-hidden="true"></i>장바구니
                    </h4>
                  </div>
                  <div id="goodsList">
                    <div class="card mb-2" onclick="location.href='#'">
                      <div class="row no-gutters">
                        <div class="col-4" style="background: #868e96;">
                          <img
                            src="https://cdn.pixabay.com/photo/2016/09/07/19/54/wines-1652455_1280.jpg"
                            class="card-img-top h-100"
                            alt="..."
                          />
                        </div>
                        <div class="col-8">
                          <div class="card-body py-1">
                            <div class="card-title row mt-2">
                              <p class="font-weight-bold col" style="display: inline">
                                상품 1
                              </p>
                              <span class="card-price col text-right">$6.20</span>
                            </div>
                            <div class="form-group row mr-0">
                              <div class="col-7 pr-2">
                                <button class="btn btn-outline-sparta btn-block">
                                  삭제
                                </button>
                              </div>
                              <!--                                    <label for="numberSelect" class="col col-form-label">수량</label>-->
                              <select class="custom-select col-5" id="numberSelect">
                                <option selected value="1">1</option>
                                <option value="2">2</option>
                                <option value="3">3</option>
                              </select>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  <hr />

                  <div class="row mb-3">
                    <div class="col-5">총 상품금액</div>
                    <div class="col-7 text-right" id="priceSum">$6.20</div>
                  </div>
                  <button type="button" class="btn btn-sparta btn-block" onclick="order()">
                    구매
                  </button>
                </div>
              </body>
            </html>
            
            

router폴더에 있는 goods.js에 추가 1

--> 장바구니에 데이터를 넣기 위한 api

        const Cart = require("../schemas/cart");

      router.post("/goods/:goodsId/cart", async (req, res) => {
        const { goodsId } = req.params;
        const { quantity } = req.body;

        isCart = await Cart.find({ goodsId });
        console.log(isCart, quantity);
        if (isCart.length) {
          await Cart.updateOne({ goodsId }, { $set: { quantity } });
        } else {
          await Cart.create({ goodsId: goodsId, quantity: quantity });
        }
        res.send({ result: "success" });
      });

이 부분에서 데이터를 post받음 --> 비동기 할당방식

router.post("/goods/:goodsId/cart", async (req, res) => {
        const { goodsId } = req.params;
        const { quantity } = req.body;
        
        

--> goodsId는 url을 통해서 받음 --> 코드의 구조상 그 데이터의 id가 path에 나타나기 때문( 이전의 코드 참고 )
--> quantity는 body에 들어있는 데이터를 통해서 받음 --> post형식의 api에 request할 때 body에 담은 데이터


이 부분에서 장바구니에 추가하려는 데이터가 mongoDB에 이미 있는지 확인함

   isCart = await Cart.find({ goodsId });
            console.log(isCart, quantity);
            if (isCart.length) {
              await Cart.updateOne({ goodsId }, { $set: { quantity } });
            } else {
              await Cart.create({ goodsId: goodsId, quantity: quantity });
            }
            res.send({ result: "success" });
          });

--> 데이터가 이미 있다면 해당 데이터에 quantity부분만 수정 --> 개수 부분]

Cart.updateOne({ goodsId }, { $set: { quantity } });
---> goodsId에 해당하는 데이터의 quantity부분을 덮어씌움

--> 데이터가 없다면 해당 id와 quantity를 포함하여 데이터를 삽입

Cart.create({ goodsId: goodsId, quantity: quantity });


router폴더에 있는 goods.js에 추가 2

--> 장바구니에 있는 데이터를 가져오기 위한 api

    router.get("/cart", async (req, res) => {
    const cart = await Cart.find({});
    const goodsId = cart.map(cart => cart.goodsId);

    goodsInCart = await Goods.find()
      .where("goodsId")
      .in(goodsId);

    concatCart = cart.map(c => {
      for (let i = 0; i < goodsInCart.length; i++) {
        if (goodsInCart[i].goodsId == c.goodsId) {
          return { quantity: c.quantity, goods: goodsInCart[i] };
        }
      }
    });

    res.json({
      cart: concatCart
    });
  });

이 부분에서 Cart(mongoDB)에 있는 데이터를 모두 가져온 후, id만 추려낸다.

    router.get("/cart", async (req, res) => {
    const cart = await Cart.find({});
    const goodsId = cart.map(cart => cart.goodsId);
    

--> 즉, 장바구니에 있는 데이터들의 id가 goodsId 변수에 리스트형식으로 할당된다.


이 부분에서 전체 데이터(mongoDB)에서 장바구니에 있는 데이터에 해당하는 정보들이 가져와진다.

    goodsInCart = await Goods.find()
      .where("goodsId")
      .in(goodsId);

--> Cart DB에는 goodsId와 quantity밖에 없다
--> Goods DB에는 goodsId, 이미지주소, 제목, 등등 해당 goodsId에 대응하는 상품에 대한 정보가 있다.

--> 따라서 Cart에 담긴 goodsId에 대한 정보들을 바탕으로 Goods 에서 해당 삼품에 대한 정보들을 가져와 goodsInCart에 저장한 것이다.


이 부분에서 Cart에서 가져온 데이터와 Goods에서 가져온 데이터를 goodsId를 기준으로 Join한다.

    concatCart = cart.map(c => {
      for (let i = 0; i < goodsInCart.length; i++) {
        if (goodsInCart[i].goodsId == c.goodsId) {
          return { quantity: c.quantity, goods: goodsInCart[i] };
        }
      }
    });
    
    

이 부분에서 cart 라는 이름으로 json형태로 데이터가 생성되어 response 된다.

      res.json({
            cart: concatCart
          });
          
          

장바구니에 있는 데이터 삭제

router폴더에 있는 goods.js에 추가

    router.delete("/goods/:goodsId/cart", async (req,res)=>{
      const { goodsId } = req.params;

      const isGoodsInCart= await Cart.find({ goodsId });
      if (isGoodsInCart.length > 0){
        await Cart.deleteOne({goodsId});
      }

      res.send({result : "success"});
    })
    

--> mongoDB에서 데이터를 삭제하기 위한 delete 표현의 api

--> delete의 특징 --> post같은 표현과 다르게 get표현처럼 일반적으로 body를 사용하지 않음
--> 누구를 지우겠다만 필요 ==> 추가적인 정보가 필요없기 떄문

--> 삭제하려는 데이터가 DB에 존재하는지 확인후
아래의 코드를 통해 제거

  await Cart.deleteOne({ goodsId });
  
  
  

데이터를 삭제하는 표현 delete

데이터를 삭제하는 api에서 사용한다.
--> 자세한 사용은 바로 위 코드 참고


장바구니에 있는 데이터에서 수량부분이 갱신되도록 설정

--> 수량 부분이 바뀌면 바뀐 내용이 mongoDB에 저장되도록 할것임

cart.ejs에서 해당 영역을 맡는 부분 html, js코드

        $(`#numberSelect-${item["goodsId"]}`).change(function() {
              // console.log(parseInt($(this).val()))
              $.ajax({
                type: "PATCH",
                url: `/api/goods/${item["goodsId"]}/cart`,
                data: {
                  quantity: parseInt($(this).val())
                },
                success: function(response) {
                  if (response["result"] == "success") {
                    console.log(response["msg"]);
                    getSum();
                  }
                }
              });
            });

--> goodsId를 바탕으로 데이터를 구분한 상태에서 수량부분의 변경을 감지하면
request를 보냄

request의 내용

                type: "PATCH",
                url: `/api/goods/${item["goodsId"]}/cart`,
                data: {
                  quantity: parseInt($(this).val())
                },
                
                
                

request에 대해 성공적으로 처리되어 response를 받았을 떄의 내용

                 success: function(response) {
                  if (response["result"] == "success") {
                    console.log(response["msg"]);
                    getSum();
                  }
                  

참고 --> getSum함수 --> 개수에 따라 값을 변경하는 함수로 구성함

          function getSum() {
          let $prices = $(".card-price");
          let $selects = $("select");
          if ($prices.length != $selects.length) {
            console.log("길이가 맞지 않습니다.");
            return;
          }
          let sum = 0;
          for (let i = 0; i < $prices.length; i++) {
            let price = parseFloat(
              $($prices[i])
                .text()
                .replace("$", "")
            );
            let count = parseInt($($selects[i]).val());
            // console.log(price, count)
            sum += price * count;
          }
          $("#priceSum").text("$" + number2decimals(sum));
          sessionStorage.setItem("priceSum", number2decimals(sum));
        }

위 코드의 request를 받기 위해 router폴더에 goods.js파일에 넣은 api코드

          router.patch("/goods/:goodsId/cart", async (req,res) =>{
            const {goodsId} = req.params;
            const {quantity} = req.body;

            const isGoodsInCart = await Goods.find({goodsId});
            if (isGoodsInCart.length > 0){
              await Cart.updateOne({ goodsId },{$set: {quantity}})
            }

            res.send({ result : "success" });
          })
          

--> 업데이트 하려는 데이터가 mongoDB에 존재하는지 확인
--> 있다면 아래의 코드를 통해 mongoDB에 있는 해당 데이터를 업데이트

     await Cart.updateOne({ goodsId },{$set: {quantity}})
     

---> goodsId가 담고있는 내용과 일치하는 데이터에 대해 quantity부분을 quantity가 담고있는 데이터로 바꾼다는 뜻
( 일종의 비동기 할당방식이라고 볼 수 있다. )

데이터를 업데이트하는 표현 put과 patch

--> DB에 있는 데이터를 수정할 경우에 put과 patch를 모두 사용할 수 있는데,
일반적으로는 둘을 구분해서 사용한다. ( 반드시 그럴 필요는 없음 )

put

보통 해당 데이터의 내용 전체를 수정할 때 사용한다.

--> 예를 들어)
id, 이름, 나이, 성별, 주소 라는 5가지 속성을 가지는 스키마의 DB의 경우

id = 25인 데이터를 수정한다고 쳤을 때
put을 사용하면 ( 25, 임수지, 27, 여, 두꺼비집 ) 처럼 해당 스키마의 속성 모두를 입력하여 데이터를 수정한다.

patch

보통 해당 데이터의 일부 내용을 수정할 때 사용한다

--> 예를 들어)
id, 이름, 나이, 성별, 주소 라는 5가지 속성을 가지는 스키마의 DB의 경우

id = 25인 데이터를 수정한다고 쳤을 때
patch을 사용하면 ( 25, 두꺼비집 ) 처럼 해당 데이터의 일부 속성을 수정한다.
---> 여기서 두꺼비집이라는 값을 '주소'라는 변수에 담아 넣는 것으로 해당 스키마의 속성에 대해 비동기 할당하여 어느 속성에 대한 값을 변경할지 나타낸다.

profile
ㅎㅎ
post-custom-banner

0개의 댓글