이 게시글은 아래와 같은 구조를 구현하기 위한 방법을 알려드립니다
글을 기준으로 알려드리지만
결국 댓글, 카테고리 도 같은 구조로 구현 가능합니다.
이름만 변경하시면 됩니다
글 => 답글 => 답답글 => 답답답글....
댓글 => 대댓글 => 대대댓글 => 대대대댓글....
카테고리 => 2단계 카테고리 => 3단계 카테고리....
원글 : http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
구글 번역글 : http://hmjkor.tistory.com/472
번역글 : https://wooriworld2006.tistory.com/417
저는 원글과 구글 번역글을 참고해서 이 게시글을 작성했습니다
글 생성시 먼저 자신의 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개의 글이 필요하다면, 조회 방법은 다음과 같습니다.
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,
}
};
여분이 포함된 게시글을 조회합니다
SELECT *
FROM post
ORDER BY lft DESC
LIMIT {limit}
OFFSET {offset};
결과값을 results
라고 부르겠습니다.
results를 부모-자식 관계에 맞게 lft와 rgt를 통해 정렬합니다
반복문과 조건문을 사용해주세요
end_index = (start_index + page_length) - 1
results
에서 start_index
부터 end_index
까지 게시글을 구합니다.
그 후 여분을 제거한 results
를 반환합니다