티스토리 뷰

우선, 카테고리를 나타내는 페이지가 있는 만큼 카테고리 이름이 잘 뽑아지도록 JOIN을 해줘야한다.

category 테이블과 books 테이블을 조인해서, category_id에 맞는 category_name이 뽑아지도록 해주었다.

( category 테이블의 name => category_name 으로 변경 )

foreign Key 설정하기

JOIN 해주기

diagram 수정

category 테이블의 id 1개 당 books 테이블의 category_id는 다수가 존재하므로 다대일 로 설정해주었다.

 

let sql = 'SELECT * FROM books LEFT JOIN category ON books.category_id = category.id WHERE books.id=?;';

개별 도서 조회에서 카테고리를 뿌려주기 위해 sql구문도 수정해주었다.

category_id에 맞는 category_name이 잘 나오는 걸 볼 수 있다.

 

💥 데이터베이스 시간 범위 구하기

 - 시간 더하기

DATE_ADD(기준날짜, INTERVAL ___ )

ex) DATE_ADD("2024-12-01", INTERVAL 1 MONTH)

 

 - 시간 빼기

DATE_SUB(기준날짜, INTERVAL ___ )

ex) DATE_ADD("2024-12-01", INTERVAL 1 MONTH)

기준날짜가 "2024-12-01" 이고, INTERVAL은 1 MONTH(1달)로 SELECT을 했을 때,

2025-01-01 이라는 데이터가 나오는 걸 볼 수 있다.

 

이번 프로젝트에서는 DATE_SUB 를 사용하여 최근 1달 이내에 출간한 도서는 신간으로 뽑히도록 만들어보았다.

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

신간을 뽑는 조건은 pub_date를 사용하니까 WHERE 뒤에 pub_date를 넣었다.

시간 범위를 지정하기 위해선 BETWEEN 을 썼다.

 

즉, 해당 sql 구문은 pub_date가 1달 전부터 오늘까지인 데이터를 뽑아달라. 라는 뜻이다.

오늘인 13일 기준 1달이내 의 데이터만 뿌리기 때문에

pub_date가 2024-11-13 ~ 2024-12-13 인 데이터를 뿌려주는 걸 볼 수 있다.

 

💥 신간 도서 출력해보기

let {category_id, newBook} = req.query;

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

    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();
            }
    })

위의 코드를 보면 우선 가장 위에 있는 sql 엔 전체 도서를 조회하는 구문을 넣었다.

 

그 이후, category_id와 newBook이 있다면 'SELECT * FROM books' 뒤에  => 카테고리별 신간 조회

'WHERE category_id=? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()';

구문이 추가되게 로직을 짰다.

 

category_id만 있다면 'SELECT * FROM books' 뒤에  => 카테고리별 도서 조회

'WHERE category_id=?' 구문이 추가될 것이다.

 

newBook만 있다면 'SELECT * FROM books' 뒤에  => 신간 조회

'WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()' 구문이 추가된다.

 

이렇게 구문이 추가되는 if-else if 문을 쓸 땐 위치에 따라 오류가 날 수 있으니, 실수하지 않도록 조심하자!

 

주소창을 보면 category_id만 들어간 걸 볼 수 있다. 그럼 신간 구분 없이 category_id 가 0 인 데이터만 나온다.

 

이 주소창은 category_id와 newBook=true 이기 때문에 category_id 가 0 이고 신간인 데이터가 나온다.

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

- 페이징 :  몇 개씩 보여줄까?

ex) SELECT * FROM books; => 전체 도서 리스트

8개씩 필요한데... 또는 4개씩 필요한데... 이럴 땐 어떻게 할까?

 

그건 바로.........

LIMITOFFSET 을 이용해야한다.

 

- LIMIT = 출력할 행의 수(몇 개씩 주겠다)

- OFFSET = 시작지점

ex) SELECT * FROM books LIMIT 3 OFFSET 0;

 

OFFSET은 0부터 시작하기 때문에 첫 번째부터 3개를 뿌려주겠다 라고 한다면 OFFSET은 0 으로 적어야한다!

 

ex) SELECT * FROM books LIMIT 4 OFFSET 0;  => 1페이지(4개씩)

ex) SELECT * FROM books LIMIT 4 OFFSET 4;  => 2페이지(4개씩)

ex) SELECT * FROM books LIMIT 4 OFFSET 8;  => 3페이지(4개씩)

 

SELECT * FROM books LIMIT 8, 4; 로 줄여서 사용도 가능! 대신 OFFSET 값이 먼저 나와야함

let {category_id, newBook, limit, currentPage} = req.query;

let offset = limit * (currentPage-1);

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

이렇게 로직을 짠 후, 포스트맨으로 확인을 해보니 오류가 났다.

야! sql 이상하잖아! 다시 확인해! 라는 에러였다.

그래서 자세히 봤더니 LIMIT 값에 숫자 4 가 아닌 '4'(문자열4)로 들어간 것이었다.

그래서 values에 있는 limit를 parseInt(limit)로 변경 후 코드를 좀 더 수정한 후 다시 돌려보았다.

 

let {category_id, newBook, limit, currentPage} = req.query;

let offset = limit * (currentPage-1);

let sql = "SELECT * FROM books";
let values = [];
if(category_id && newBook){
    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 (newBook) {
    sql += " WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()";
}

sql += " LIMIT ? OFFSET ?";
values.push(parseInt(limit), offset);

category_id=0&newBook=true  => category_id가 0 이고 신간인~

limit=4&currentPage=1  => 첫 번째부터 4개씩 보여주세요.

즉, category_id가 0이고 신간인 첫 번째 도서부터 4개씩 보여주세요. 라는 뜻이다.

데이터를 보아하니 category_id가 0 이고, pub_date가 1달이내인 걸 볼 수 있다.

 

오늘은 신간 도서 조회와 페이징을 구현해보았다.
지금 따로 준비하고 있는 프로젝트에도 페이징을 나타내는 기능이 필요해서 순간, 프로젝트가 생각났다.
본인은 지금 프론트쪽을 담당하고 있기 때문에 해당 코드들을 사용하진 않겠지만,
프로젝트를 하면서 해당 구문이나 코드가 보인다면 뭔가 굉장히 반가울 것 같다😏

이번 강의는 꽤나 헷갈리고 어려운 부분이 좀 있었다.
수정도 많이 했고 오류도 자주났었다. 강의를 멈추고 혼자 고쳐보기도 하고 구글링도 하고 그랬다...
하지만 거의 90%는 오타였다 😑 항상 오타에 주의하자..
오늘 습득한 지식들은 굉장히 잘 사용할 것으로 보인다.
어느 페이지에서나 무한로딩이 아닌 이상 페이징은 기본이고, 데이터를 뿌려주는 데 가장 유용한 기능이 아닐까 싶다.
그러니 오늘 강의는 나중에 시간이 난다면 한 번 더 돌려보면서 혼자서 코드를 짜보는 것도 좋을 것 같다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함