댓글 기능은 어떻게 만들까요?
당연히 댓글 기능 만드는 법을 배워야 만들 수 있는게 아니라...
알아서 해오십시오 새로운거 없습니다.
일단 어떻게 동작하는지 설명부터 해보자면
1. 글마다 밑에 input이랑 전송버튼이 있고 누르면 서버로 댓글이 전송
2. 그럼 서버는 댓글을 DB에 저장
3. 상세페이지 방문시 댓글을 가져와서 보여주기
근데 댓글은 DB 어디에 저장하면 좋을지 생각해봅시다.
초보 때는 "DB에 이렇게 저장해도 될까" 많이 생각을 할텐데
나중에 데이터가 많아져도 출력/수정/삭제가 쉬우면 잘 저장한 것입니다.
댓글은 글 document 안에 저장해도 될듯
당연히 A라는 글에 달린 댓글은
A라는 document 안에 필드 하나 새로 만들어서 저장해도 됩니다.
(DB에 있는 글 document)
{
title : '어쩌구',
content : '어쩌구',
comment : [ '댓글1', '댓글2', '댓글3' ]
}
여러 문자를 한 곳에 저장하려면 array자료형으로 집어넣어도 됩니다.
댓글 작성자나 날짜도 저장하고 싶으면 object 집어넣어서 [ { }, { }, { } ] 이런 식으로 저장해도 됩니다.
하지만 이러면 댓글이 1억개 달릴 경우 문제가 있습니다.
1. DB에 있는 array 자료형은 원하는 항목 하나만 수정, 삭제하는게 매우 어렵습니다.
2. document 하나는 16MB의 데이터까지 저장할 수 있음
3. array는 일부만 찾아오는 것도 불가능합니다. 한 번에 1억개 다 가져와야함
그래서 이런 식으로 필드에 적을 자료가 너무 길어질 것 같으면
다른 컬렉션을 만들어서 document로 옮기는 것도 좋습니다.
다른 document로 옮기기
▲ 이렇게 댓글들을 별도의 document로 저장하는게 어떨까요.
그럼 아까 문제들을 해결할 수 있지 않을까요?
왜냐면 DB가 가장 잘하는게 document 빠르게 찾아오는 것이기 때문에
이러면 댓글이 나중에 1억개 되어도 원하는 것만 빠르게 찾아올 수 있습니다.
Q. 근데 그럼 이 댓글이 어떤 글에 달렸던 댓글인지 모르는데요?
모르겠으면 표기해주면 되는 것 아닙니까
▲ 댓글마다 부모 글이 뭐였는지 표기해서 저장해두면 됩니다.
이러면 나중에 _id가 1인 글의 댓글을 가져오고 싶으면
{ 부모게시물_id : 1 }인 댓글 document 가져오라고 코드짜면 될 것 같습니다.
그래서 중요한 점이 하나 있는데
document안에 들어갈게 매우 많아서 나중에 수정, 삭제, 출력이 어려울 것 같으면 따까리 document 형태로 저장해둡시다.
그리고 따까리들을 만들 때 원래 어떤 document에 있었는지 (부모가 누구였는지) 잘 기록해두면 문제없습니다.
그래서 강의 끄고 댓글기능을 알아서 만들어옵시다.
제 코드 따라치기만 하면 따라치는실력만 느는 것임
알아서 해보고 제 코드와 한 번 비교해봅시다.
댓글기능 1. 댓글 UI 만들기
일단 1번기능부터 구현해보면 댓글 보여줄 부분이랑 댓글 작성할 인풋을 만들어봅시다.
(detail.ejs)
<div class="detail-bg">
<h4><%= result.title %></h4>
<p><%= result.content %></p>
<hr style="margin-top: 60px">
<div>
<p><strong>작성자</strong> 댓글내용</p>
</div>
<form action="/comment" method="POST">
<input name="content">
<input name="parentId" value="<%= result._id %>" style="display: none">
<button type="submit">댓글작성</button>
</form>
</div>
저는 이런 식으로 detail.ejs 파일에 만들어봤습니다.
전송누르면 댓글이 서버로 전송되어야할텐데
서버는 댓글내용, 부모게시물 _id, 작성자 정보를 DB에 저장해놔야하니까 이것들도 다 보내봅시다.
근데 작성자 정보는 서버에서 출력하는게 나아서
댓글내용, 부모게시물 _id 정도만 서버로 전송해봤습니다.
댓글기능 2. 서버는 댓글을 db에 저장
누가 /comment로 POST 요청하면 그걸 db에 저장해봅시다.
comment 컬렉션에 저장해봅시다.
app.post('/comment', async (요청, 응답)=>{
let result = await db.collection('comment').insertOne({
content : 요청.body.content,
writerId : new ObjectId(요청.user._id),
writer : 요청.user.username,
parentId : new ObjectId(요청.body.parentId)
})
응답.redirect('back')
})
이렇게 해봤습니다.
그럼 댓글전송해보면 댓글이 DB에 잘 저장됩니다.
- POST 요청 응답시 이전페이지로 다시 이동하고 싶으면
그 이전페이지 URL을 여기 적어야하는데 그걸 잘 모르겠으면 redirect('back') 이라고 쓰면 됩니다.
그걸 어떻게 알았냐면 당연히 검색해봤을 뿐이고요
댓글 기능 3. 상세페이지 방문시 댓글도 꺼내 보여줌
app.get('/detail/:id', async (요청, 응답) => {
let result = await db.collection('post').findOne({ _id : new ObjectId(요청.params.id) })
let result2 = await db.collection('comment').find({ parentId : new ObjectId(요청.params.id) }).toArray()
응답.render('detail.ejs', {result : result, result2 : result2})
})
누가 상세페이지 방문시 그 글의 댓글도 꺼내서 result2라는 이름으로 ejs파일에 전송해봤습니다.
모든 댓글을 가져오는게 아니라 parentId : 현재게시물_id 라고 기재된 댓글만 가져왔습니다.
(detail.ejs)
<% for (let i = 0; i < result2.length; i++) { %>
<p><strong><%= result2[i].writer %></strong> <%= result2[i].content %></p>
<% } %>
detail.ejs 페이지에선 result2라고 쓰면 댓글들이 다 나오니까 그걸 반복문 돌려서 보여줘봤습니다.
댓글이 잘 보이나 테스트해봅시다.
그래서 오늘 배운거 정리해보면
- document에 array자료형으로 여러 정보를 기록할 수 있습니다.
근데 너무 많아질거같으면 다른 document로 빼면 되는데 원래 어떤 부모 document에 속해있었는지만 기록해두면 됩니다.
오늘의 응용사항 :
Q1. 댓글 전송시 새로고침없이 댓글이 반영되게 만들고 싶으면?
지금은 댓글 전송시 새로고침이 되는데 AJAX 사용해서 새로고침 없이 댓글을 저장하고
댓글저장 완료시 새로운 댓글 내용을 html에 박아넣어주면 더 부드러운 사이트가 될 것 같군요.
'Node.js' 카테고리의 다른 글
node>채팅기능 만들기 1 (채팅방이 뭐임) (0) | 2024.09.19 |
---|---|
node>Node+Express 서버와 React 연동하려면 (1) | 2024.09.19 |
node>게시판에 회원기능을 넣자 & 비정규화 (0) | 2024.09.19 |
node>검색기능 만들기 3 (search index) (0) | 2024.09.19 |
node>검색기능 만들기 2 (index 설명) (0) | 2024.09.19 |