[BookShop 프로젝트] - 도서목록 조회 페이지 구현 - MySQL 시간 범위 구하기, DB 페이징(paging)

https://ilove-ya.tistory.com/152

 

[BookShop 프로젝트] Books API 구현 - picsum

전체 도서 조회const allBooks = (req, res)=> { //(요약된) 전체 도서 리스트 -> 부분적으로 뽑는 건 프론트엔드 let sql = "SELECT * FROM books"; conn.query(sql, (err, results) => { if(err) { console.log(err); return res.status(Statu

ilove-ya.tistory.com

이 글에서 이어집니다!

 


books-category 연관관계 설정

books의 category_id : category의 PK를 FK로 가지고 있음

Books에서 FK 설정

 

LEFT JOIN 

 

SELECT * FROM books LEFT JOIN category ON books.category_id = category.id;

books을 기준으로 오른쪽에 books.category_id = category.id에 맞게 JOIN을 해줍니다. 


추가로 WHERE 조건 넣어 하나만 출력 가능합니다. 

SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.id=1;

조인된 것들 중에 책 id가 1인 정보만 SELECT되어 보여집니다. 

 

sql 문법 헷갈린다면 -> https://ilove-ya.tistory.com/133


이를 코드에 적용해봅시다. 

const bookDetail = (req, res)=> {
    let {id} = req.params;

    let sql = "SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.id=?";
    conn.query(sql, id,
        (err, results) => {
        if(err) {
            console.log(err);
            return res.status(StatusCodes.BAD_REQUEST).end(); 
        }

        if(results[0]){
            return res.status(StatusCodes.OK).json(results[0]);
        }
    
        else {
            return res.status(StatusCodes.NOT_FOUND).end();
        }
    })
};

 

이전에는 밑의 SQL문을 사용하여 단순히 books 정보를 가져왔는데, LEFT JOIN으로 category 정보까지 함께 가져오도록 하였습니다. 

SELECT * FROM books WHERE id = ?
 

category_name이 추가된 걸 볼 수 있습니다. 이로써 프론트엔드는 바로 category_name을 바로 꺼내다 화면에 보여줄 수 있겠습니다. 


시간 범위 설정으로 신간 도서 뽑아내기 - 데이터베이스 시간 범위 구하기

  • 시간 더하기 DATE_ADD(기준 날짜, INTERVAL _____)
  • 시간 빼기 DATE_SUB(기준 날짜, INTERBAL _____)
  • NOW() 지금 시각

 

SELECT DATE_ADD("2026-01-02", INTERVAL 1 DAY);
SELECT DATE_ADD("2026-01-02", INTERVAL 1 MONTH);
SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH);

 

우리 프로젝트에서 필요한 건 

"현재 날짜에서 한 달 전" 이후에 출간된 책을 뽑아내는 것입니다. 이 때에 이 "현재 날짜에서 한 달 전"은

DATE_SUB(NOW(), INTERVAL 1 MONTH);

이렇게 표현해줄 수 있겠죠? 

SELECT * FROM books WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW();

최종으로 이렇게 해주면,

현재 날짜에서 한달 전 ~ 현재 의 정보가 보여집니다.


신간 여부 판단해주는 코드 작성해보겠습니다.


// (카테고리 별, 신간 여부) 전체 도서 목록 조회
const allBooks = (req, res)=> {
    let {category_id, news} = req.query;

    let sql = "SELECT * FROM books";
    let values = [];
    if(category_id&&news){
        sql += " WHERE category_id = ? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
        values = [category_id, news]
    }
    else if(category_id) {
        sql += " WHERE category_id = ?";  
        values = category_id;
    }      
    else if(news) {
        sql += " WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()"
        values = news;
    }

    // 카테고리 별 시간 조회 
    conn.query(sql, values,
        (err, results) => {
        if(err) {
            console.log(err);
            return res.status(StatusCodes.BAD_REQUEST).end(); 
        }

        if(results.length){
            return res.status(StatusCodes.OK).json(results);
        }
    
        else {
            return res.status(StatusCodes.NOT_FOUND).end();
        }
    })

};


도서 목록 조회 페이징 구현

데이터베이스 페이징(paging)

페이징 : 필요한 양만큼 잘라서 제공해주는 것. 

  • LIMIT : 출력할 행의 수 
  • OFFSET : 시작 지점
SELECT * FROM books LIMIT 3 OFFSET 0;

SELECT * FROM books LIMIT 0, 3;

> 0번째 열부터(id가 아닌 0부터 시작) 3개를 출력해줘!

 

페이징 구현(페이지 당 5개)

: LIMIT을 고정,  OFFSET을 0에서 LIMIT만큼 더해주면 됩니다. 

-> 첫번째 페이지 

SELECT * FROM books LIMIT 5 OFFSET 0;

SELECT * FROM books LIMIT 0, 5;

-> 두번째 페이지

SELECT * FROM books LIMIT 5 OFFSET 5;

SELECT * FROM books LIMIT 5, 5;

-> 세번째 페이지

SELECT * FROM books LIMIT 5 OFFSET 10;

SELECT * FROM books LIMIT 10, 5;

front에게 limit(page당 도서 수) currentPage(현재 몇 페이지인지)를 받는 다고 했을 때 offset

limit :         ex. 3
currentPage :   ex. 1, 2, 3...
offset :        ex. 0, 3, 6, 9, 12... -> limit * (currentPage - 1)
// (카테고리 별, 신간 여부) 전체 도서 목록 조회
const allBooks = (req, res)=> {
    let {category_id, news, limit, currentPage} = req.query;

    let offset = limit * (currentPage - 1);

    let sql = "SELECT * FROM books";
    let values = [];
    if(category_id&&news){
        sql += " WHERE category_id = ? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
        values = [category_id];
    }
    else if(category_id) {
        sql += " WHERE category_id = ?";  
        values = [category_id];
    }      
    else if(news) {
        sql += " WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()"
    }

    sql += " LIMIT ? OFFSET ?"; //WHERE절 뒤에 있어야함
    values.push(parseInt(limit), offset);
    
    //... 생략
    }