본문 바로가기
타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js)/TIL

데브코스 8주차 Day4 - 좋아요 수/여부 조회(서브쿼리), 좋아요 기능 추가

by 슈크림 붕어빵 2024. 1. 7.

구현한 부분

  • 도서 좋아요 및 좋아요 삭제 기능 추가 (테이블 추가)
  • 도서 목록 조회 시 좋아요 수 & 좋아요 여부 연동
  •  정리
    • 도서 목록 조회
      • 검색조건: 전체 / 카테고리별 (where) / 신간 (where) 
      • 타 테이블 참조: likes,liked (서브쿼리)
    • 개별 도서 조회
      • 타 테이블 참조: likes, liked (서브 쿼리)
      • 타 테이블 참조: 카테고리명(left join)

서브쿼리

  • Join 없이 다른 테이블의 정보와 함께 SELECT
  • 서브쿼리 (쿼리 안 쿼리) - 쿼리의 결과값을 바깥 쿼리에 사용
  • 원리
    • SELECT 컬럼명1,컬럼명2 .. FROM 테이블명
    • SELECT *, ( 각 행마다 likes 테이블에 liked_book_id로 가지고 있는 행 수 ) FROM books

ex) books 정보 + 해당 book id의 좋아요 수

SELECT * , (SELECT count(*) FROM likes WHERE liked_book_id=books.id) AS likes
 FROM Bookshop.books;

 

ex) 개별 도서 조회 - 좋아요수, 좋아요 여부(서브쿼리), 카테고리명(left join)

SELECT * , 
(SELECT count(*) FROM likes WHERE liked_book_id=books.id) AS likes,
(SELECT count(*) FROM likes WHERE user_id=1 AND liked_book_id=1) AS liked
 FROM Bookshop.books 
 LEFT JOIN category 
 ON books.category_id=category.category_id
 WHERE books.id=1;

workbench확인

 

존재 여부?

 

다음 두가지 방법은 결과는 같다.

 

1. SELECT EXISTS 이용

SELECT EXISTS (SELECT * FROM likes WHERE user_id=1 AND liked_book_id=1) AS isexist

결과

2. count(*)이용

SELECT count(*) FROM likes WHERE user_id=1 AND liked_book_id=1

결과

BookController.js

const conn = require("../mariadb");
const { StatusCodes } = require("http-status-codes");

const allBooks = (req, res) => {
  const { category_id, new_book, limit, current_page } = req.query;
  let offset = limit * (current_page - 1);

  let sql =
    "SELECT *, (SELECT count(*) FROM likes WHERE liked_book_id=books.id) AS likes FROM books";
  let values = [];
  if (category_id && new_book) {
    sql +=
      " WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(),INTERVAL 1 MONTH) AND NOW()";
    values.push(category_id);
  } else if (new_book) {
    sql += " WHERE pub_date BETWEEN DATE_SUB(NOW(),INTERVAL 1 MONTH) AND NOW()";
  } else if (category_id) {
    sql += " WHERE category_id=?";
    values.push(category_id);
  }
  sql += "LIMIT ? OFFSET ?";
  values.push(parseInt(limit), parseInt(offset));

  conn.query(sql, values, (err, results) => {
    if (err) {
      console.log(err);
      return res.status(StatusCodes.BAD_REQUEST).end();
    }
    if (results.length > 0) {
      return res.status(StatusCodes.OK).json(results);
    } else {
      return res.status(StatusCodes.NOT_FOUND).end();
    }
  });
};
//개별 도서 조회
const book = (req, res) => {
  let { user_id } = req.body;
  const { id: book_id } = req.params;
  let sql = `SELECT * , 
  (SELECT count(*) FROM likes WHERE liked_book_id=books.id) AS likes,
  (SELECT count(*) FROM likes WHERE user_id=? AND liked_book_id=?) AS liked
   FROM Bookshop.books 
   LEFT JOIN category 
   ON books.category_id=category.category_id
   WHERE books.id=?;`;
  let values = [user_id, book_id, book_id];

  conn.query(sql, values, (err, results) => {
    if (err) {
      console.log(err);
      return res.status(StatusCodes.BAD_REQUEST).end();
    }
    if (results.length > 0) {
      return res.status(StatusCodes.OK).json(results);
    } else {
      return res.status(StatusCodes.NOT_FOUND).end();
    }
  });
};

module.exports = {
  allBooks,
  book,
};

 

id가 많아짐에 따라 어떤 id인지 알아보기 쉽게 비구조화시 명칭을 지어주었다.

const { id: book_id } = req.params;