프로젝트/SSR 게시판

[프로젝트] 게시판 | 8. 게시물 댓글 수 보여주기&댓글 기준으로 인기 게시물 보여주는 법

paintover23 2024. 1. 19. 17:51
728x90

 

위와 같이 게시물에 달린 댓글의 수와 댓글 수가 많이 담긴 게시물을 내림차순으로 정렬하여 화면 우측에 보여주고자 한다.

 

Part1. 게시물 당 달린 댓글 수 보여주는 법

사고과정

1. 하나의 comment 데이터에는 댓글이 속한 게시물을 의미하는 부모 id(parentId)를 포함되어 저장되어 있다.

2. 서버에서 post 데이터를 모두 불러온뒤 각 post의 id가 comment의 parentId와 일치하는 모든 댓글을 가져온다.

3. 단, 댓글이 없는 게시물은 굳이 가져올 필요가 없으므로 2번에서 comment의 length가 1개 이상인 댓글만을 가져온다.

4. 데이터를  ejs 파일로 렌더링 시켜준다.

 

완성코드

(list.js)

router.get('/total', isLogin, async (req, res) => {
  let commentCount = {};

  try {
    let loginuser = req.user ? new ObjectId(req.user._id) : null;
    let posts = await db.collection('post').find().toArray();

    // 게시글 당 댓글 수 구하기
    for (const post of posts) {
      let comments = await db
        .collection('comment')
        .find({ parentId: post._id })
        .toArray();

      // 댓글 달린 것만 보냄
      if (comments.length > 0) {
        commentCount[post._id] = comments.length; // 키와 밸류
      }
    }

    return res.render('listTotal.ejs', {
      boardPosts: posts,
      loginUser: loginuser,
      commentCount: commentCount,
    });
  } catch (e) {
    console.log(e);
  }
});

 

1. comment가 달린 post의 id와 해당 post 에 담긴 댓글 수를 key-value로 보여주는 빈 객체 commentCount를 try 구문 밖에 만든다.

2. for..of 구문을 활용하여 post 배열을 순회하면서 parentId:post._id 와 일치하는 모든 comments 를 가져오자.

3. 2번에서 comment의 개수는 1개 이상인 것을 가져오면서, 아래와 같이 post._id 를 키 값으로, comment 의 개수를 value로 갖는 commentCount 객체에 구해진 데이터들을 차례대로 넣어준다. 콘솔을 찍으면 다음과 같이 표시된다:

 

(commentCount 객체안에 넣는 형식)

commentCount[post_.id] = comments.length // key-value
// console.log('commentCount', commentCount)

commentCount {
  '65a9c9214a833bc7b6643f99': 1,
  '65a9c9404a833bc7b6643f9a': 1,
  '65a9c9cc4a833bc7b6643f9e': 2,
  '65a9c9fb4a833bc7b6643f9f': 2,
  '65a9ca684a833bc7b6643fa1': 1,
  '65a9ca954a833bc7b6643fa2': 3,
  '65a9cb2c4a833bc7b6643fa4': 3,
  '65a9cb734a833bc7b6643fa7': 1,
  '65a9cbd04a833bc7b6643faa': 1
}

 

 

(listTotal.ejs)

<div class="editNdelete">
    <div><%=boardPosts[i].category%></div>
    <a class="mainTitle" href="/detail/<%=boardPosts[i]._id%>"
      ><%=boardPosts[i].title %></a
    >
    <% for (const key in commentCount) { %>
      <% if (key === boardPosts[i]._id.toString()) { %>
        <span>(<%= commentCount[key] %>)</span>
      <% } %>
    <% } %>
    
 // 중략...

 

4. 서버로 부터 전달받은 commentCount는 객체이므로 for..in 구문을 활용하여 하나씩 순회한다.

5. key 값( =post의 id)가 boardPosts(= 다른 서버로 부터 전달받은 게시글 목록)의 id와 일치하면, commentCount[key]를 통해 각 key의 value 값을(=즉, 댓글 수) 화면에 보여준다. 

 

 

Part2. 댓글 기준으로 인기 게시물 보여주는 법

이번에는 전술한 댓글 수 보여주기 기능을 응용해 댓글이 많은 순서대로 인기 게시물을 보여주는 기능을 구현해보겠다.

구현 방식은 거의 유사하지만 클라이언트 측에서 댓글 수를 내림차순으로 정렬해주는 방식이 추가된다.

 

(listTotal.ejs)

<div class="white-bg">
          <div class="grid2titleBox">
            <div class="grid2Title">인기 TOP 게시물</div>
            <div class="grid2subTitle">한주간 서비스에서 인기있던 게시물이에요!</div>
          </div> 
          <% if(commentCount) { %>
            <!-- sort 메소드 사용을 위한 객체를 배열로 변경 -->
            <% let commentArray = Object.entries(commentCount) %>
            <% commentArray.sort((a,b) => b[1]-a[1]) %>
            <% console.log('commentArray',commentArray) %>

            <% for(let m = 0; m < 8 && m < commentArray.length; m++) { %>
              <% for(let l=0; l< boardPosts.length; l++) { %>
                <% if(commentArray[m][0]=== boardPosts[l]._id.toString()) { %>
                  <div class="grid2Box">
                    <div class="rank"><%=m+1%></div>
                    <div class="grid2Profile"><img src="<%=boardPosts[l].userImage%>" alt="이미지"></div>
                    
                      <div class="topPosts">
                        <a href="/detail/<%=boardPosts[l]._id%>">
                          <div class="topPostsTitle"><%=boardPosts[l].title%></div>
                          <div class="topPostsContent"><%=boardPosts[l].content%></div>
                        </a>
                      </div>
                  </div>
                <% } %>
              <% } %> 
            <% } %>
          <% } %>
</div>

 

1. 서버로부터 전달받은 commentCount 데이터를 댓글 수를 기준으로 내림차순 정렬하기 위해서는 sort() 메소드를 사용할 수 있다. 그러나 sort()는 배열에 사용되는 메소드 이므로, 사전작업으로 객체인 commentCount를 배열로 먼저 바꾸어줘야 한다. 

let commentArray = Object.entries(commentCount)

 

Object.entries(commentCount)를 사용하여 객체를 배열로 바꾸어주었다. 콘솔을 찍으면 다음과 같이 객체가 이차원 배열로 바뀐다:

commentArray [
  [ '65a9c9214a833bc7b6643f99', 1 ],
  [ '65a9c9404a833bc7b6643f9a', 1 ],
  [ '65a9c9cc4a833bc7b6643f9e', 2 ],
  [ '65a9c9fb4a833bc7b6643f9f', 2 ],
  [ '65a9ca684a833bc7b6643fa1', 1 ],
  [ '65a9ca954a833bc7b6643fa2', 3 ],
  [ '65a9cb2c4a833bc7b6643fa4', 3 ],
  [ '65a9cb734a833bc7b6643fa7', 1 ],
  [ '65a9cbd04a833bc7b6643faa', 1 ]
]

 

2. sort 메소드를 활용해 위의 배열을 댓글 수(= value) 값을 기준으로 내림차순 해보자.

commentArray.sort((a,b) => b[1]-a[1])

 

- 내림차순은 sort((a,b)=> b-a)를 활용하면 된다. 여기서는 value값을 기준으로 내림차순 하기 때문에 각 요소의 [1]index를 참조한다.

- 콘솔을 찍으면 다음과 같이 내림차순 된다!

commentArray [
  [ '65a9ca954a833bc7b6643fa2', 3 ],
  [ '65a9cb2c4a833bc7b6643fa4', 3 ],
  [ '65a9c9cc4a833bc7b6643f9e', 2 ],
  [ '65a9c9fb4a833bc7b6643f9f', 2 ],
  [ '65a9c9214a833bc7b6643f99', 1 ],
  [ '65a9c9404a833bc7b6643f9a', 1 ],
  [ '65a9ca684a833bc7b6643fa1', 1 ],
  [ '65a9cb734a833bc7b6643fa7', 1 ],
  [ '65a9cbd04a833bc7b6643faa', 1 ]
]

 

3. 이제는 part1과 같이 key값(=post id) 가 boardPosts의 id 와 일치할 경우 해당하는 post의 글과 콘텐츠를 가져오면 된다.

for(let m = 0; m < 8; m++) {

 

- 보기 좋도록 최대 8개 까지만 인기 게시물을 가져오겠다. 

- 헌데, 이렇게 작성하니 다음과 같은 오류가 나타난다. 

TypeError:
    316|             <% for(let m=0; m< 8; m++) { %>
    317|               <% for(let l=0; l< boardPosts.length; l++) { %>
 >> 318|                 <% if(commentArray[m][0]=== boardPosts[l]._id.toString()) { %>
    319|                   <div class="grid2Box">
    320|                     <div class="rank"><%=m+1%></div>
    321|                     <div class="grid2Profile"><img src="<%=boardPosts[l].userImage%>" alt="이미지"></div>

Cannot read properties of undefined (reading '0')

 

- Array 내용이 분명 있는데도 [0]의 값을 읽지 못하고 있다. 그 이유는 서버에서 가져온 commentCount의 길이가 예컨대 3개 일때, for문을 돌며 3개 까지는 정상적으로 읽히지만, 범위가 8이 될때까지 반복하므로 3개를 넘어가면 데이터를 읽지 못하는 현상이 발생하기 때문이다. 이러한 문제를 예방하기 위해서는 범위로 commentCount의 길이도 함께 설정해주어야 한다.

for(let m = 0; m < 8 && m < commentArray.length; m++) {

 

- 이렇게 설정하면 정상적으로 동작하게 된다.

 

 

 

 

 

728x90
반응형