TIL Node.js로 query문 작성하여 데이터 조회,수정,삭제

ESH'S VELOG·2023년 7월 31일
0

오늘은 키오스크의 등록된 메뉴들을 조회, 수정, 삭제하는 작업을 하려고 한다.

1) 조회
조회는 따로 req할 내용이 없고 res로 조회 값만 반환해주면 되기에 controller와 service는 간단하게 repository로 방향을 옮겨준다.

아래는 repository에서 작성된 메뉴를 모두 조회하는 쿼리를 적용한 코드이다.

getItem = async () => {
    try {
      const sql = 'SELECT * FROM item';
      const allItems = await expressApp.dbConnection.query(sql);
      return allItems;
    } catch (error) {
      throw error;
    }
  };

실행해 봤더니, 문제가 발생하였다.

1) created_at과 updated_at이 null로 생성되지 않는 것을 발견
2) 이상한 buf라는 데이터가 추가 배열로 들어왔다는 점

우선 1)번은 아예 테이블을 만들어주려고 하였다.
테이블 생성 시 값이 추가가 될 때 디폴트값으로 생성 또는 수정되는 시간으로 자동 저장이 되게끔 설정할 것이다.

CREATE TABLE IF NOT EXISTS item (
    id SMALLINT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    option_id BIGINT,
    price INT NOT NULL,
    type ENUM('COFFEE','TEA','JUICE','SMOOTHIE') NOT NULL,
    amount SMALLINT NOT NULL DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY(id)
);


테이블의 created_at과 updated_at의 default값을 설정해주니 값이 null이 아닌 현재 시간을 기준으로 저장되는 것이 확인되었다.

2번 문제 해결

getItem = async () => {
    try {
      const sql = 'SELECT * FROM item';
      const allItems = await expressApp.dbConnection.query(sql);
      return allItems[0];
    } catch (error) {
      throw error;
    }
  };

데이터를 반환할 시에 첫 번째(배열에서는 0번째)값만 반환하게 해주었다. 뒤에 데이터는 아마 레코딩 데이터라 예상되는데 배열로 들어오기때문에 0번째만 반환하게 해주었다.

잘 반환하는 것을 확인하였다.

type 별 조회하기

  • express의 query속성 이용
    예상도:
    주소 localhost:3000/api/item/type?COFFEE
    Controller에서 type을 주소로부터 받아와 repository에서 where절로 찾아오기!

순서는 다음과 같이 진행하였다.
1) npm i body-parser
=> 쓰는 와중에 body-parser에 대해 구글링해봤는데 익스프레스 4.15.0버전부터 이 기능이 익스프레스에 내장되어 따로 설치할 필요가 없다고 한다..
2) app.js에서 body-parser기능 실행할 수 있게하기

import bodyParser from 'body-parser';

class ExpressApp {
	app= express()
    dbConnection;
    setAppsettings = () => {
    this.app.use(express.json());
    this.app.use(bodyParser.json());
    this.app.use(bodyParser.urlencoded({extended:false}));
}
  • urlencoded는 주소 형식으로 데이터를 보내는 방식이다.(req)
    => 즉 내가 주소(url)형식으로 type을 보낼 때 그 주소를 해석할 수 있게 해주는 방식이다. false는 노드의 querystring 모듈을 사용하여 쿼리스트링을 해석하고, true면 qs모듈을 사용하여 쿼리를 해석한다고 한다. 나는 노드를 사용하기 때문에 false를 사용하였다

** qs모듈은 npm패키지이며 querystring 모듈의 기능을 좀 더 확장한 모듈이라 한다.

이제 쿼리스트링을 읽을 수 있게 해주었으니 라우터차례

3) 라우터 주소 추가

router.get('/item/type', itemController.getTypeItem);

4) Controller에서 query를 받아오기

getTypeItem = async (req, res, next) => {
    try {
      const { type } = req.query;
      console.log(type);
      const typeAllItems = await this.itemService.getTypeItem(type);
      res.status(200).json({ data: typeAllItems });
    } catch (error) {
      console.error(error);
      return res
        .status(500)
        .json({ message: '메뉴 타입별 조회에 실패하였습니다.' });
    }
  };

5) Repository에서 받은 쿼리를 where절로 찾아서 반환해주기

getTypeItem = async (type) => {
    try {
      const sql = 'SELECT * FROM item where type=?';
      const typeAllItems = await expressApp.dbConnection.query(sql, [type]);
      return typeAllItems[0];
    } catch (error) {
      throw error;
    }
  };

6) 테스트 해보기

http://localhost:3000/api/item/type?type=JUICE


type이 JUICE인 값만 잘 받아와졌다.

처음에는 http://localhost:3000/api/item/type?JUICE 으로 했더니 type이 undefined값으로 받아졌었다.

그 이유를 찾아보니 다음과 같다.

  • Query String 개념부터 파악해보기
    사용자가 입력데이터를 전달하는 방버 중 하나로 url주소에 미리 협의된 데이터를 파라미터로 통해 넘기는 것을 말한다
    http://~//path?querystring
    url에서 ? 다음에 오는 내용이 querystring이며 ?뒤에 나오는 문자열을 서버에 보내줄 수 있다
    구조는 키1=값1 key=value형식으로 구성되어 있고, 여러 개를 사용하려면 &을 사용하면 된다.
    내가 보내준 url은 즉 value값만 있고 key값이 없는 상태인 것이다.
    http://localhost:3000/api/item/type?type=JUICE
    로 보내주면 쿼리스트링, key=value값이 모두 들어있기에 실행이 가능했다.

메뉴 수정하기

이번에는 url의 param을 받아 수정을 하려고 한다.

express의 속성 param을 받아 수정
router에서 put 사용, url은 /item/:id
controller에서 params와 req.body를 사용하여 수정할 내용을 전달
repository에서 UPDATE query문을 사용하여 update된 값을 반환

router

router.put('/item/:id', itemController.modifyItem);

controller

modifyItem = async (req, res, next) => {
    const { id } = req.params;
    const { name, price, type, amount } = req.body;
    try {
      const updateItem = await this.itemService.modifyItem(
        name,
        price,
        type,
        amount,
        id
      );
      return res.status(200).json({ data: updateItem });
    } catch (error) {
      console.error(error);
      return res.status(500).json({ message: '메뉴 수정에 실패하였습니다.' });
    }
  };

service

modifyItem = async (name, price, type, amount, id) => {
    try {
      return await this.itemRepository.modifyItem(
        name,
        price,
        type,
        amount,
        id
      );
    } catch (e) {
      console.error(e);
      throw error;
    }
  };

repository

modifyItem = async (name, price, type, amount, id) => {
    try {
      const sql =
        'UPDATE item SET name=?, price=?, type=?, amount=? where id =?';
      const updateItem = await expressApp.dbConnection.query(sql, [
        name,
        price,
        type,
        amount,
        id,
      ]);
      return updateItem[0];
    } catch (error) {
      throw error;
    }
  };

sql문으로 값을 update하고 싶으면 아래와 같이 작성하면 된다.
UPDATE table명 SET 컬럼명1, 컬럼명2, 컬럼명3, where 수정할 곳

문제발생) return으로 updateItem을 넣으니 이상한 값이 반환되었다.

업데이트 된 row가 반환된 것이 아니고 수정된 레코드를 반환하는 것 같다.

문제해결) update한 item을 다시 select해 보여주는 쿼리를 변수에 할당하여 수정된 메뉴를 반환하게 해주었다.

const updateItemQuery = 'SELECT * FROM item WHERE id =?';
const updatedItem = await expressApp.dbConnection.query(updateItemQuery, [
        id,
      ]);
      return updatedItem[0];

수정해야 할 점
=> 메뉴를 수정 시 가격만 수정하거나 type만 수정하거나 client가 모든 것을 입력하지 않아도 될 수 있게 바꿔야 한다. 만약 빈 값을 넣으면 빈 값으로 들어가니 이 부분이 아쉽다.

메뉴 삭제하기

id를 params로 받아 repository에서 delete 와 where절을 사용하여 쿼리문으로 삭제 처리

router

router.delete('/item/:id', itemController.deleteItem);

controller

deleteItem = async (req, res, next) => {
    const { id } = req.params;
    try {
      await this.itemService.deleteItem(id);
      return res
        .status(200)
        .json({ message: `id: ${id}의 메뉴가 삭제되었습니다.` });
    } catch (error) {
      console.error(error);
      return res.status(500).json({ message: '메뉴 삭제에 실패하였습니다.' });
    }
  };

repository

deleteItem = async (id) => {
    try {
      const sql = 'DELETE FROM item WHERE id =?';
      await expressApp.dbConnection.query(sql, [id]);
    } catch (error) {
      throw error;
    }
  };

==== 데이터 삭제하는 방법

DELETE FROM 테이블 이름 WHERE ?

삭제기능까지 완료하였따.

profile
Backend Developer - Typescript, Javascript 를 공부합니다.

1개의 댓글

comment-user-thumbnail
2023년 7월 31일

이런 유용한 정보를 나눠주셔서 감사합니다.

답글 달기