当前位置: 首页 > 知识库问答 >
问题:

java - 如何实现根据评论id将某条评论置顶?

龚沛
2024-07-16
@Data
@Document("db_comment")
public class DbComment  {
    @Id
    private ObjectId id;
    // 创建时间
    private LocalDateTime createdAt;
    // 更新时间
    private LocalDateTime updatedAt;
    // 删除标识
    private Boolean deleted;
    // 删除时间
    private LocalDateTime deletedAt;
    // 父评论id
    private ObjectId parentId;
    // 该评论的用户id
    private ObjectId userId;
    // 评论内容
    private String content;
    // 点赞的数量
    private Integer likeCount;
    // 回复的数量
    private Integer replyCount;
    // 评论类型  作品评论/文章评论
    private CommentTypeEnum resourceType;
    // 评论目标id 作品/文章
    private ObjectId resourceId;
    // 资源作者
    private ObjectId resourceAuthorId;
    // 是否为作者评论
    private Boolean isAuthor;
    //  回复用户id
    private ObjectId replyToUserId;
} 

这是我的评论表结构,在分页查询时,需要查询父级评论并查询文章作者的二级评论。当cid存在时,又需要将该条评论在第一页置顶,如果cid为二级评论时需要将父评论置顶,并将该评论展示出来,我可以一次将该文章下的所有评论查询出来,在代码中遍历分页,可这种操作非常占用内存效率也低。我又不希望关联查询,mongo的复杂查询很麻烦。这个cid存在时,我可以单独的对该条评论做两次查询,然后组装成commentVo 加到commentVos顶部 可这份数据又会造成多次的user信息以及是否喜欢信息的查询,还要处理Cursor以及Count结果,当c我应该怎么实现这份功能,下面的代码我并没有写当cid存在时将该条评论置顶的业务逻辑,因为很困惑!

 /**
     * @param commentListQuery
     * @return
     */
    @Override
    public R<CommentResultVo> getList(CommentListQuery commentListQuery) {
        ObjectId cid = commentListQuery.getCid();
        ObjectId resourceId = commentListQuery.getResourceId();
        Integer resourceType = commentListQuery.getResourceType();
        Integer cursor = commentListQuery.getCursor();
        Integer count = commentListQuery.getCount();

        ObjectId userId = StpUtil.isLogin()?new ObjectId(StpUtil.getLoginIdAsString()):null;

        Criteria criteria = where(DbComment.Fields.resourceId).is(resourceId).and(DbComment.Fields.resourceType).is(resourceType).and(DbComment.Fields.parentId).isNull();
        long total = commentMapper.selectCount(query(criteria));

        // 获取一级评论总数
        Query query = query(where(DbComment.Fields.resourceId).is(resourceId).and(DbComment.Fields.resourceType).is(resourceType).and(DbComment.Fields.parentId).isNull());
        query.skip(cursor);
        query.limit(count);
        query.with(Sort.by(Sort.Direction.DESC, BaseEntity.Fields.createdAt));

        List<DbComment> dbComments = commentMapper.selectList(query);


        List<ObjectId> commentIds = ConvertUtils.resultToList(dbComments, DbComment::getId);
        List<ObjectId> userIds = ConvertUtils.resultToList(dbComments, DbComment::getUserId);

        List<DbUser> dbUsers = userMapper.selectByIds(userIds);
        Map<ObjectId, DbUser> userMap = ConvertUtils.listToMap(dbUsers, DbUser::getId);
        // 点赞的评论ids
        List<ObjectId> likeCommentIds = new ArrayList<>();

        if (Objects.nonNull(userId)) {
            List<DbLike> dbLikes = likeMapper.selectLikes(userId, commentIds, ResourceTypeEnum.COMMENT);
            for (DbLike dbLike : dbLikes) {
                likeCommentIds.add(dbLike.getId());
            }
        }

        List<CommentVo> commentVos;
        try(ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()){
            List<CompletableFuture<CommentVo>> futures = dbComments.stream()
                    .map(dbComment -> CompletableFuture.supplyAsync(() -> {
                        CommentVo commentVo = new CommentVo();
                        commentVo.setId(dbComment.getId());
                        commentVo.setUserId(dbComment.getUserId());
                        if (Objects.nonNull(dbComment.getUserId())){
                            DbUser user = userMap.get(dbComment.getUserId());
                            if (Objects.nonNull(user)){
                                UserVo userVo = UserJson.toVo(user);
                                commentVo.setUser(userVo);
                            }
                        }

                        commentVo.setContent(dbComment.getContent());
                        commentVo.setReplyCount(dbComment.getReplyCount());
                        commentVo.setLikeCount(dbComment.getLikeCount());
                        commentVo.setLike(likeCommentIds.contains(dbComment.getId()));
                        commentVo.setAuthor(dbComment.getIsAuthor());
                        commentVo.setCreatedAt(dbComment.getCreatedAt());
                        commentVo.setUpdatedAt(dbComment.getUpdatedAt());

                        // 查询每个父评论的前三条子评论
                        Query childQuery = query(where(DbComment.Fields.parentId).is(dbComment.getId()).and(DbComment.Fields.isAuthor).is(true));
                        childQuery.with(Sort.by(Sort.Direction.DESC, BaseEntity.Fields.createdAt));
                        childQuery.limit(1);
                        commentVo.setSubComment(getSubComments(childQuery, userId));

                        return commentVo;
                    }, executor))
                    .toList();
             commentVos = futures.stream()
                    .map(CompletableFuture::join)
                    .collect(Collectors.toList());
        }catch (Exception e){
            commentVos= Collections.emptyList();
        }

        CommentResultVo pagerVo = new CommentResultVo();
        pagerVo.setCursor(cursor + dbComments.size());
        pagerVo.setCount(commentVos.size());
        pagerVo.setTotal(total);
        pagerVo.setComments(commentVos);
        pagerVo.setHasMore(cursor + commentVos.size() < total);
        return R.data(pagerVo);
    }

共有1个答案

裴钧
2024-07-16

要在不改变现有查询逻辑太多并且不需要进行关联查询的情况下,实现根据评论ID置顶评论的功能,你可以采取以下步骤:

  1. 查询置顶评论:在原始查询之前,首先根据传入的cid(如果存在)查询置顶评论(及其父评论,如果cid是二级评论)。
  2. 构建置顶列表:将查询到的置顶评论(及其父评论)转化为CommentVo对象,并存储在一个临时列表中。
  3. 执行原始查询:按照你现有的逻辑执行原始查询,获取分页的评论列表。
  4. 合并列表:将置顶评论列表插入到原始分页列表的顶部。
  5. 调整分页信息:如果置顶评论列表中的评论数量大于请求的分页数量,可能需要调整分页的游标和总数。

以下是代码示例,展示了如何添加置顶逻辑:

// ... 其他代码 ...

// 1. 查询置顶评论
List<CommentVo> pinnedComments = new ArrayList<>();
if (Objects.nonNull(cid)) {
    // 查询置顶评论,并根据需要查询其父评论
    DbComment pinnedComment = commentMapper.selectById(cid); // 假设有selectById方法
    if (pinnedComment != null) {
        CommentVo pinnedCommentVo = convertToCommentVo(pinnedComment, userMap, likeCommentIds, userId);
        pinnedComments.add(pinnedCommentVo);
        
        // 如果cid是二级评论,查询其父评论
        if (Objects.nonNull(pinnedComment.getParentId())) {
            DbComment parentComment = commentMapper.selectById(pinnedComment.getParentId());
            if (parentComment != null) {
                CommentVo parentCommentVo = convertToCommentVo(parentComment, userMap, likeCommentIds, userId);
                // 可以将父评论放在置顶列表的前面或后面,取决于你的需求
                pinnedComments.add(0, parentCommentVo); // 添加到列表前面
            }
        }
    }
}

// 2-5. 剩余逻辑...

// 在原始查询之后,合并置顶列表
List<CommentVo> finalCommentVos = new ArrayList<>(pinnedComments);
finalCommentVos.addAll(commentVos);

// 如果置顶评论数量大于分页数量,你可能需要调整分页信息
if (pinnedComments.size() > count) {
    // 这里可以返回置顶评论的完整列表,或者调整cursor和total以适应设为置顶评论
    // 例如,将cursor0,total设为pinnedComments.size(),并返回pinnedComments
}

// ... 其他分页逻辑和返回结果 ...

// 辅助方法,用于将DbComment转换为CommentVo
private CommentVo convertToCommentVo(DbComment dbComment, Map<ObjectId, DbUser> userMap, List<ObjectId> likeCommentIds, ObjectId userId) {
    // 转换逻辑,类似于你的CompletableFuture中的代码
    // ...
    return commentVo;
}

注意:上述代码只是一个概念性示例,并且假设了一些方法和字段的存在。你需要根据你的实际代码库进行调整。特别是,你可能需要调整convertToCommentVo方法以匹配你的具体需求。此外,分页逻辑(如cursor和total的调整)可能需要根据你的具体需求进行定制。

 类似资料:
  • 获取所有评论 GET /comments 请求查询参数: 名字 类型 描述 limit integer 可选,本次请求需要返回的数据条数。 index integer 可选,查询开始的评论位置,来源响应 id 字段。 direction string 可选,数据排序方向,以 id 进行排序,支持 asc 或 desc,默认 desc。 author integer 可选,需要筛选的评论作者,传递

  • 评论一条资讯 获取一条资讯的评论列表 删除一条资讯评论 评论一条资讯 POST /news/{news}/comments 参数 名称 描述 body 评论内容 reply_user 被回复用户id 默认为0 Response Headers Status: 201 Created { "message": [ "操作成功" ], "comment": { "use

  • 获取问题评论列表 获取回答评论列表 评论问题 评论答案 删除问题评论 删除回答评论 获取问题评论列表 GET /questions/:question/comments 参数 名称 类型 描述 limit Integer 默认 20 ,获取列表条数,修正值 1 - 30。 after integer 默认 0 ,筛选偏移, 上一次获取的评论列表中最后一条的id 响应 Status: 200 OK

  • 音乐评论列表 专辑评论列表 添加音乐评论 添加专辑评论 删除音乐评论 删除专辑评论 音乐评论列表 GET /music/{music}/comments Parameters 名称 类型 描述 limit Integer 可选,默认值 15 ,获取条数 max_id Integer 可选,上次获取到数据最后一条 ID,用于获取该 ID 之后的数据。 Response Status: 200 OK

  • Send comment Get all comments Get a single comment Delete comment Send comment POST /feeds/:feed/comments Input Name Type Description body String Comment body. reply_user Integer Reply comment to use

  • 一、简介 增加用户与用户,用户与管理员互动与交流。 二、功能演示 1.评论模块配置 2.评论管理 以一篇新闻的评论为例: 管理操作如下: 你可以根据自己的需要进行配置和操作。