최초 작성일 : 2021-09-25 | 수정일 : 2021-10-05 | 조회수 : |
이 게시글은 아래와 같은 구조를 구현하기 위한 방법을 알려드립니다
글을 기준으로 알려드리지만
결국 댓글, 카테고리 도 같은 구조로 구현 가능하다.
이름만 변경하시면 됩니다글 => 답글 => 답답글 => 답답답글.... 댓글 => 대댓글 => 대대댓글 => 대대대댓글.... 카테고리 => 2단계 카테고리 => 3단계 카테고리....
원글 : http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
구글 번역글 : http://hmjkor.tistory.com/472
번역글 : https://wooriworld2006.tistory.com/417저는 원글과 구글 번역글을 참고해서 이 게시글을 작성했다
DB 구조
글 생성
글 생성시 먼저 자신의
lft
,rgt
정보가 필요하다.
다만lft = rgt - 1
- 부모가 없는 원글 생성일때
SELECT MAX(rgt) AS max_rgt FROM post;
rgt = max_rgt + 1
입니다rgt
,lft
를 가지고 게시글을 생성한다
- 부모가 있는 자식글 생성
먼저 부모 글을 조회한다.
SELECT * FROM post AS parent WHERE post_id = {parent_id}
rgt = parent.rgt + 2
입니다생성하기전에 게시글이 들어갈 자리를 비워야한다
부모글의 오른쪽 글들을 한칸씩 옮길 필요가 있습니다Transaction
을 이용한다UPDATE post SET lft=lft+2 WHERE ltf > {parent.rgt}
UPDATE post SET rgt=rgt+2 WHERE rgt >= {parent.rgt}
rgt
,lft
를 가지고 게시글을 생성한다글 수정
글 제목, 내용 수정시 크게 주의할 사항은 필요하지 않다.
글 수정시 자식 존재시 수정 불가능 기능이 필요하시면
자식 글 조회 후 처리하시면 된다.글 삭제
글 삭제시 자식글 전체 삭제 또는 자식 존재시 삭제 불가능 기능이 필요하시면
자식 글 조회 후 처리하시면 된다.
삭제 글, 오른쪽 글들의lft
,rgt
의 변경을 원하신다면 아래를 참고해주세요
(삭제된 post의 오른쪽 글을 왼쪽으로 한칸 옮기는 기능)UPDATE post SET rgt = rgt - (CASE WHEN (rgt > {post.rgt}) THEN 2 WHEN (lft > {post.lft} AND rgt < {post.rgt}) THEN 1 ELSE 0 END)
UPDATE post SET lft = lft - (CASE WHEN (lft > {post.rgt}) THEN 2 WHEN (lft > {post.lft - 1} AND rgt < {post.rgt - 1}) THEN 1 ELSE 0 END)
글 목록 조회
MySQL
과Javascript
를 기준으로 작성한다.게시글 정렬시 원글끼리의 정렬방법과 자식끼리의 정렬방법이 다릅니다.
보통 일반적인 게시판은 아래와 같이 정렬됩니다.
depth 제목 작성일 1단계 제목 01/07 1단계 제목 01/06 1단계 애국가 01/02 2단계 [답글]동해물과 01/03 2단계 [답글]백두산이 01/04 2단계 [답글]마르고 01/05 1단계 제목 01/01 위 예시를 살펴보면
1. 1단계(원글)는 최신글이 앞으로 정렬
2. 2단계(자식)는 최신글이 뒤로 정렬
정렬방법이 서로 다른걸 확인 할 수 있다.SELECT * FROM post ORDER BY lft DESC;
위와 같은 쿼리는 원글 정렬은 만족하지만 자식 정렬은 만족하지 못한다
먼저 두가지 값이 필요하다.max_depth
: 최대 깊이max_count_per_depth
: 단계당 최대 글 개수
두 값 모두 필수이며, 최대 크기 제한이 필요한다
글 생성시max_depth
와max_count_per_depth
를 체크해주세요또한 게시글 전체 조회 기능을 막으시고
page_num
(현재 페이지 넘버)와page_length
(한 페이지 당 길이)를 필수값으로 사용해주세요자식이 영원히 늘어날 수 없으며, 한번에 전체를 조회 할 수 없게 한다.
위 4가지 값을 통해, 목록 조회시 필요한offset
과limit
을 구한다 (MySQL
기준)만약 n개의 글이 필요하다면, 조회 방법은 다음과 같다.
- 여분의 길이 를 구한다.
- n + 여분 길이의 글을 DB에서 가져온다
- 부모-자식을 정렬 한다
- 필요없는 여분의 게시글을 제거한다
1. 여분의 길이를 구한다
function getExtraLength(page_num, page_length, max_depth, max_count_per_depth) { let start_index = max_depth * max_count_per_depth; let offset = (page_num - 1) * page_length; let limit = parseInt(limit) + extra_length; if (offset > extra_length) { start_index = extra_length; offset = (offset - front_minus) || 0; limit += extra_length; } return { offset, limit, start_index, } };
여분이 포함된 게시글을 조회한다
2. SELECT
SELECT * FROM post ORDER BY lft DESC LIMIT {limit} OFFSET {offset};
결과값을
results
라고 부르겠습니다.3. 부모-자식 정렬
results를 부모-자식 관계에 맞게 lft와 rgt를 통해 정렬한다
반복문과 조건문을 사용해주세요4. 여분 제거
end_index = (start_index + page_length) - 1
results
에서start_index
부터end_index
까지 게시글을 구한다.
그 후 여분을 제거한results
를 반환한다