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

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

  • 说明:按照指定字段进行排序,然后对所有记录进行分组,选择每个分组最后一个文档,然后对所有选中的文档进行分页和条件查询等。(此处只是通过聚合操作实现,实际增加一个冗余字段“是否为最新版本”即可)
 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,详情参考代码
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MongoDB 是一种 NoSQL 数据库,它使用 JSON 类型的文档来存储数据。而 FreeMarker 是一种模板引擎,它可以根据模板和数据生成静态文本或者动态网页。 要实现 MongoDB + FreeMarker 的条件查询,可以按照以下步骤进行: 1. 在 MongoDB 中定义一个集合,用于存储数据。 2. 使用 MongoDBJava 驱动程序连接到数据库,并获取集合的句柄。 3. 使用 Java 代码编写查询条件,并将查询结果存储到一个 List 对象中。 4. 将 List 对象作为数据模型,将 FreeMarker 模板和数据模型合并,生成最终的输出。 下面是一个示例代码,演示了如何使用 MongoDB 和 FreeMarker 进行条件查询: ``` // 连接到 MongoDB 数据库 MongoClient mongoClient = new MongoClient("localhost", 27017); // 获取集合的句柄 MongoDatabase database = mongoClient.getDatabase("mydb"); MongoCollection<Document> collection = database.getCollection("mycollection"); // 定义查询条件 BasicDBObject query = new BasicDBObject(); query.put("name", "John"); // 执行查询,并将结果存储到 List 对象中 List<Document> results = new ArrayList<>(); FindIterable<Document> cursor = collection.find(query); for (Document doc : cursor) { results.add(doc); } // 将 List 对象作为数据模型,渲染 FreeMarker 模板 Configuration cfg = new Configuration(Configuration.VERSION_2_3_28); cfg.setDirectoryForTemplateLoading(new File("templates")); Template template = cfg.getTemplate("mytemplate.ftl"); Map<String, Object> dataModel = new HashMap<>(); dataModel.put("results", results); Writer out = new OutputStreamWriter(System.out); template.process(dataModel, out); out.flush(); ``` 在上面的代码中,我们使用了 BasicDBObject 类来定义查询条件。在这个示例中,我们只查询了 name 属性等于 "John" 的文档。你可以根据自己的需求修改查询条件。 最后,我们将查询结果存储到一个 List 对象中,并将它作为数据模型,渲染 FreeMarker 模板。在模板中,你可以使用 ${results} 变量来访问查询结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值