부트모아

[V1] 셀프 조인을 통한 대댓글 구현

승무_ 2024. 9. 28. 14:40

게시글의 댓글 기능을 단순히 후기만을 올리는 것이 아니라 사용자 간의 질문 및 정보 공유 바탕으로 상호작용하게 하고 싶었다. 그러기 위해서는 대댓글 기능이 필요할것 같다는 생각이 들었고 이를 구현해 보았다.

 

먼저 위 같이 댓글의 관계를 그림으로 표현한 후, 이를 어떻게 구현할지 고민하다가 데이터베이스 수업시간에 배운 self join을 이용해 보기로 했다. 

 

public class ArticleComment {
	
    ```
    
    @Setter
    private Long parentCommentId;

    @ToString.Exclude
    @OrderBy("createdAt ASC")
    @OneToMany(mappedBy = "parentCommentId", cascade = CascadeType.ALL)
    private Set<ArticleComment> childComments = new LinkedHashSet<>();
    
    ```
}

위와 같이 댓글과 대댓글을 1:N 관계라 생각하고 매핑해주었다. 

 

comment 테이블을 살펴보면 위와 같이 댓글과 대댓글의 계층 상태가 표현 되어있지 않다. 최종적으로 view에 내려줄 때는 계층 상태로 내보내주어야 하기 때문에 converting logic이 필요하다.

 

private static Set<ArticleCommentResponse> organizeChildComments(Set<ArticleCommentDto> dtos) {
        Map<Long, ArticleCommentResponse> map = dtos.stream()
                .map(ArticleCommentResponse::from)
                .collect(Collectors.toMap(ArticleCommentResponse::getId, Function.identity()));

        map.values().stream()
                .filter(ArticleCommentResponse::hasParentComment)
                .forEach(comment -> {
                    ArticleCommentResponse parentComment = map.get(comment.getParentCommentId());
                    parentComment.getChildComments().add(comment);
                });

        return map.values().stream()
                .filter(comment -> !comment.hasParentComment())
                .collect(Collectors.toCollection(() ->
                        new TreeSet<>(Comparator
                                .comparing(ArticleCommentResponse::getCreatedAt)
                                .reversed()
                                .thenComparingLong(ArticleCommentResponse::getId)
                        )
                ));
    }

 

1. 데이터에 쉽게 접근하기 위해 dto를 response로 mapping한 후 key는 id, value는 response로 변환시켜준다.

2. 부모가 있는 댓글을 추출한 후, id를 통해 부모 댓글을 구한 뒤 자식 Set에 추가해준다.

3. 반환하기 전에 대댓글에 정렬 순서를 설정하는 작업이 필요하다.

4. map.values().stream().filter() 를 통해 자식 댓글만 뽑은 뒤,

5. Comparator에서 첫번째 비교 대상은 생성일자를 기준으로 내림차순 정렬하고, 시간이 동일할 경우를 대비하여 댓글에 id 값을 기준으로 오름차순 정렬한다.