계층형 게시판 구현하기

juna·2020년 1월 3일
6

구현하기

목록 보기
2/2

이 게시글은 아래와 같은 구조를 구현하기 위한 방법을 알려드립니다

글을 기준으로 알려드리지만
결국 댓글, 카테고리 도 같은 구조로 구현 가능합니다.
이름만 변경하시면 됩니다

글 => 답글 => 답답글 => 답답답글....
댓글 => 대댓글 => 대대댓글 => 대대대댓글....
카테고리 => 2단계 카테고리 => 3단계 카테고리....

원글 : http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
구글 번역글 : http://hmjkor.tistory.com/472
번역글 : https://wooriworld2006.tistory.com/417

저는 원글과 구글 번역글을 참고해서 이 게시글을 작성했습니다

DB 구조

계층형게시판.PNG

글 생성

글 생성시 먼저 자신의 lft, rgt 정보가 필요합니다.
다만 lft = rgt - 1

  1. 부모가 없는 원글 생성일때
SELECT MAX(rgt) AS max_rgt
FROM post;

rgt = max_rgt + 1 입니다
rgt, lft를 가지고 게시글을 생성합니다

  1. 부모가 있는 자식글 생성

먼저 부모 글을 조회합니다.

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)

글 목록 조회

MySQLJavascript를 기준으로 작성합니다

게시글 정렬시 원글끼리의 정렬방법과 자식끼리의 정렬방법이 다릅니다.
보통 일반적인 게시판은 아래와 같이 정렬됩니다.

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_depthmax_count_per_depth 를 체크해주세요

또한 게시글 전체 조회 기능을 막으시고
page_num(현재 페이지 넘버)와 page_length(한 페이지 당 길이)를 필수값으로 사용해주세요

자식이 영원히 늘어날 수 없으며, 한번에 전체를 조회 할 수 없게 합니다.
위 4가지 값을 통해, 목록 조회시 필요한 offsetlimit을 구합니다 (MySQL기준)

만약 n개의 글이 필요하다면, 조회 방법은 다음과 같습니다.

  1. 여분의 길이 를 구한다.
  2. n + 여분 길이의 글을 DB에서 가져온다
  3. 부모-자식을 정렬 한다
  4. 필요없는 여분의 게시글을 제거한다

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 를 반환합니다

profile
웹 개발자

0개의 댓글