SpringData MongoDB 分组+分页+条件查询的复杂操作

该代码示例展示了如何在MongoDB中通过聚合操作实现分组、按指定字段排序、选择每个分组的最后一个文档以及进行分页和条件查询。通过构建一系列的MongoDB聚合操作,包括GroupOperation、SortOperation和ProjectionOperation,实现了对ServiceImpl类实例的复杂查询。此外,还讨论了在分组查询中处理_id的问题,以及如何通过first或last获取分组内的特定文档。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例子:分组 + 分页 + 条件查询 + 排序操作

  • 说明:按照指定字段进行排序,然后对所有记录进行分组,选择每个分组最后一个文档,然后对所有选中的文档进行分页和条件查询等。(此处只是通过聚合操作实现,实际增加一个冗余字段“是否为最新版本”即可)
 public Pagination<ServiceImpl> findServiceImplByPage(Integer pageNum, Integer pageSize, ServiceImplQuery implQuery) {
        PageRequest pageReq = PageRequest.of(pageNum - 1, pageSize);
        SortOperation sortOperation = sort(Sort.by(Sort.Direction.ASC, "versionCode"));
        // 构建分组操作
        GroupOperation groupOperation = Aggregation.group("serviceImplId");
        // 设置需要查询的字段,getPropNameList()方法表示获取类的所有的属性名称,id除外
        List<String> propNameList = MongoUtil.getPropNameList(ServiceImplDTO.class);
        for (String s : propNameList) {
            // 注意:此处需要重新赋值,每次build创建了一个新的对象
            groupOperation = groupOperation.last(s).as(s);
        }
        // 注意:id需要特别处理否则拿不到
        groupOperation = groupOperation.last("_id").as("id");
        ProjectionOperation projectionOperation = project()
            .andExclude("_id")
            .and("id").as("_id");
        for (String s : propNameList) {
            projectionOperation = projectionOperation.and(s).as(s);
        }
        Aggregation groupAggregation = Aggregation.newAggregation(
            sortOperation,
            groupOperation,
            skip(pageReq.getOffset()),
            limit(pageReq.getPageSize()),
            projectionOperation);
        /* 构建查询条件 */
        if (implQuery != null) {
            Criteria criteria = new Criteria();
            if (CharSequenceUtil.isNotBlank(implQuery.getName())) {
                criteria.and("name").regex(".*" + implQuery.getName() + ".*");
            }
            if (implQuery.getCreateTimeSort() != null) {
                groupAggregation.getPipeline().add(sort(Sort.by(
                    MongoUtil.getSortDirection(implQuery.getCreateTimeSort()), "createTime")));
            }
            groupAggregation.getPipeline().add(match(criteria));
        }
        // 执行聚合查询
        AggregationResults<ServiceImpl> aggregationResults = mongoTemplate.aggregate(
            groupAggregation,
            mongoTemplate.getCollectionName(ServiceImpl.class),
            ServiceImpl.class
        );
        // 获取聚合结果
        List<ServiceImpl> serviceList = aggregationResults.getMappedResults();
        // 计算查询结果的总数
        Aggregation countAggregation = Aggregation.newAggregation(groupOperation, count().as("count"));
        AggregationResults<CountResult> results = mongoTemplate.aggregate(countAggregation,
              mongoTemplate.getCollectionName(ServiceImpl.class), CountResult.class);
        CountResult countResult = results.getUniqueMappedResult();
        long total = countResult != null ? countResult.getCount() : 0;
        return new Pagination<>(serviceList, pageNum, pageSize, total);
    }

注意

  • 直接通过聚合操作进行分组只能得到并不能直接得到文档,只能通过 max、min、sum等聚合操作获取相关的值
  • 如果想要获取分组内一个文档,需要使用 f i r s t 或 first或 firstlast,获取分组内第一个或最后一个文档的字段的值(前提是按照你要的方式进行排序)
  • 因为分组查询的特性,_id的值不再是文档的ObjectId,而是被用于分组的字段的值,因此需要特殊处理才能够查出ObjectId
    • 通过 first或last(“_id”).as(“identityId”),这样可以会将ObjectId写入identityId字段中,然后使用具有identityId字段的实体类接收即可
    • 通过ProjectionOperation排除默认的_id,详情参考代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值