https://www.youtube.com/watch?v=bhnDSyiPvaY&t=186s
- db 설계를 위해 위의 영상을 참고했다.
ref
는 댓글들의 그룹이므로 최신으로 정렬 (desc: 내림차순): 새로운 댓글을 달 때마다 ref+1
을 해주기 때문refOrder
는 (asc: 오름차순): 대댓글은 부모댓글의 refOrder
+1으로 추가되므로, 최신의 대댓글이 항상 적은 수기 때문
model Comment {
id String @id @default(cuid())
createdAt DateTime
content String
postId String
parentCommentId String?
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
commenterId String
image String?
name String?
ref Int @default(1)
step Int @default(0)
refOrder Int @default(0)
answerNum Int @default(0)
commenter User? @relation(fields: [commenterId, image, name], references: [id, image, name], onDelete: Cascade)
}
댓글은 최신을 가장 위로 오게 보는게 좋다고 생각한다.
따라서 댓글이든 대댓글이든 가장 위로 오게 해둔다.
경우 1: 댓글 달기
- 댓글일 경우에는 대댓글이 아니므로 부모댓글이 없다. (자식은 부모가 있어야 존대한다.)
- parentCommentId
(부모댓글 없음) 현재 그룹(ref
)+1을 해서 다음 그룹의 댓글의 ref를 지정.
refOrder
는 현재 그룹 내의 대댓글 & 댓글의 순서다.경우 2: 대댓글 달기
- parent
:부모 댓글의 모든 정보
updateChildRefOrder
: 같은 ref
그룹 내에서 순서를 조정해줘야 할 대댓글들hasChildren
: answerNum
(같은 그룹 내의 자식들 개수)의 합, 즉 각각의 댓글/대댓글들이 가진 자식의 합updateChildRefOrder
) +1ref
)에서 하나씩 그룹 순서를 +1 해줘야하는 대댓글들이 있음 (refOrder
가 현재 작성하는 대댓글보다 refOrder
가 큰 경우)import { NextApiRequest, NextApiResponse } from "next";
import prisma from "../../../lib/prisma";
// POST /api/comment
// Required fields in body: content, parentCommentId, email, postId, createdAt
export default async function handle(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
const { content, parentCommentId, email, postId, createdAt } = req.body;
/**
* 댓글이 저장될 때마다 ref의 최댓값을 찾아서 ref+1 저장
*/
const { _max } = await prisma.comment.aggregate({
where: { post: { id: postId } },
_max: { ref: true },
});
// 댓글
if (!parentCommentId) {
const comment = await prisma.comment.create({
data: {
createdAt: createdAt,
content: content,
commenter: { connect: { email: email } },
post: {
connect: { id: postId },
},
ref: _max.ref + 1,
refOrder: 0,
},
});
res.json(comment);
} else {
// 대댓글
const parent = await prisma.comment.findFirst({
where: { post: { id: postId }, id: parentCommentId },
});
const { _count } = await prisma.comment.aggregate({
where: { post: { id: postId }, ref: parent.ref },
_count: { answerNum: true },
});
const updateChildRefOrder = [];
const hasChildren = _count.answerNum;
if (hasChildren > 0) {
// 업데이트할 자식들이 있음
const children = await prisma.comment.findMany({
where: { post: { id: postId }, ref: parent.ref },
select: { id: true, refOrder: true, content: true },
});
let filt = children.filter((v) => v.refOrder >= parent.refOrder + 1);
filt.forEach(async (v) => {
let res = await prisma.comment.update({
where: { post: { id: postId }, id: v.id },
data: { refOrder: v.refOrder + 1 },
});
updateChildRefOrder.push(res);
});
}
const comment = await prisma.comment.create({
data: {
createdAt: createdAt,
content: content,
commenter: { connect: { email: email } },
post: {
connect: { id: postId },
},
ref: parent.ref,
step: parent.step + 1,
parentCommentId: parent.id,
refOrder: parent.refOrder + 1,
},
});
const updateParentChildCount = await prisma.comment.update({
where: { post: { id: postId }, id: parentCommentId },
data: { answerNum: parent.answerNum + 1 },
});
res.json([comment, updateParentChildCount]);
}
} else {
console.log("req method : ", req.method);
}
}
(다음에는 prisma+postgre+nextjs+nextOAuth(카카오+깃헙)예제한 거 정리해야할듯)