基于带replyId的评论实体如何查询嵌套层级的树形评论回复列表
实现方案
你可以通过以下三步完成平级评论到嵌套树形结构的转换:
1. 调整CommentDto类型定义
由于有子回复的评论replyId字段需要存子评论数组,需要先修改Dto的字段类型:
export class CommentDto { id: string; content: string; authorId: string; entityId: string; creatAt: Date; // 类型调整:无子回复时存父评论id/null,有子回复时存子评论数组 replyId?: string | null | CommentDto[]; type: CommentTypeEnum; }
2. 新增平级转树形结构的工具方法
在评论对应的Service类中新增转换方法,时间复杂度为O(n),性能最优:
private buildCommentTree(flatComments: CommentDto[]): CommentDto[] { // 建立id到评论对象的映射表,方便快速查找父评论 const commentMap = new Map<string, CommentDto>(); flatComments.forEach(comment => { commentMap.set(comment.id, { ...comment }); }); const rootComments: CommentDto[] = []; // 遍历所有评论,挂载到对应父节点的回复列表 flatComments.forEach(comment => { const currentComment = commentMap.get(comment.id)!; const parentId = comment.replyId; // 根评论直接加入顶层结果 if (!parentId) { rootComments.push(currentComment); return; } const parentComment = commentMap.get(parentId); // 处理找不到父评论的脏数据场景,可根据业务需求调整逻辑 if (!parentComment) return; // 父评论的replyId不是数组则先初始化 if (!Array.isArray(parentComment.replyId)) { parentComment.replyId = []; } // 将当前评论加入父评论的回复列表 (parentComment.replyId as CommentDto[]).push(currentComment); }); // 可选:如果需要统一子回复按发布时间倒序,可添加递归排序逻辑 // const sortByTime = (list: CommentDto[]) => { // list.sort((a, b) => new Date(b.creatAt).getTime() - new Date(a.creatAt).getTime()); // list.forEach(item => Array.isArray(item.replyId) && sortByTime(item.replyId)); // } // sortByTime(rootComments); return rootComments; }
3. 修改查询接口逻辑
在原有接口查询到平级评论后,调用转换方法处理后再返回:
@Get('/:entityId/comments') async getAll(@Param('entityId') entityId: string): Promise<CommentDto[]> { const comments = await this.commentRepository.find({ where: { entityId: entityId }, order: { id: 'DESC' } }); // 先转换为基础Dto格式 const flatDtos = comments.map(it => ({ id: it.id, content: it.content, authorId: it.authorId, entityId: it.entityId, creatAt: it.creatAt, replyId: it.replyId || null, type: it.type, })); // 转换为嵌套树结构后返回 return this.buildCommentTree(flatDtos); }
内容的提问来源于stack exchange,提问作者Марк
相关产品推荐
相关产品推荐

