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로 가지고 있음

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);
//... 생략
}

'Devcourse' 카테고리의 다른 글
| [BookShop 프로젝트] CartItem (0) | 2026.03.03 |
|---|---|
| [Node.js] Node.js의 비동기 처리 - Promise / Async&await (0) | 2026.02.22 |
| Express-generator 프로젝트 구조 (0) | 2026.02.13 |
| <데브코스> 2026-02-10 (0) | 2026.02.10 |
| <데브코스> 프로젝트2 - Yes24 밴치마킹 (1) | 2026.02.06 |