mongodb之使用聚合方法条件排序查询

目录

一、springboot使用聚合方法处理业务查询排序心得

二、分页代码

三、对二中condSortParam参数进行加工后的程序

五、总结


一、springboot使用聚合方法处理业务查询排序心得

  1. 思路。此文编程部分思路大部分通过文心一言(免费版本即可) 获取。
    注意:但在首次使用所给的答案绕了远路,第二回通过给他发送明确的内容做基础,如发送 mongosh脚本后 给出了编码 才拿到正确的解答方式
    注意:在springboot中使用正确的方式编程,springboot中使用aggregate方法与使用mongosh 脚本基本方法名称相同, 不然会出现问题(奇怪的问题)
  2. 如下是提的问题。询问文心一言内容
  • 注意首先编写mongosh脚本进行查询。查询结果正确后。询问文心一言获取springboot的编程代码
    如:

    shell 复制代码
    db.document.aggregate([{
            $addFields: {
                sortOrder: {
                    $cond: {
                        if: {
                            $eq: ["$status", "8"]
                        },
                        then: 1,
                        else: {
                            $cond:{
                                if: {
                                    $eq: ["$status", "9"]
                                },then: 2,
                                else: -1
                            }
                        }
                    }
                }
            }
        },
        {
            $sort: {
                sortOrder: -1,
                applyTime: -1
            }
        },{
            $project: {
                _id: 1,
                accNum: 1,
                status: 1,
                applyTime: 1
            }
        }
    ]);将上述脚本 用springboot 编程实现

二、分页代码

  • 注意:此代码为分页方法,传入的CondSortParam是经过加工后传入的,带有mongo聚合查询需要的AggregationOperation与SortOperation

  • 注意:Aggregation.newAggregation中 AggregationOperation参数的排列顺序会影像查询结果
    例如:

    排序1 查询结果会先排序后通过条件进行处理。

    复制代码
     SortOpertion, AddFieldsOpertion.....

    解决方法:倒置:AddFieldsOpertion, SortOpertion...

    java 复制代码
    /*
     * 分页公共方法
     */
    public static <T> PageVO<T> pagination(PageRequestDTO dto, Class<T> tClass,
                                               MongoTemplate mongoTemplate, CondSortParam condSortParam) {
        # 获取查询条件
        Criteria criteria = handleCriteria(dto);
        // 添加查询条件
        MatchOperation matchOperation = Aggregation.match(criteria);
        // 计算总数, 分页
        Query query = new Query();
        query.addCriteria(criteria);
        if (!ObjectUtils.allNotNull(dto.getCurrentPageNum())) {
            dto.setCurrentPageNum(0);
        }
        if (!ObjectUtils.allNotNull(dto.getSize())) {
            dto.setSize(10);
        }
        long count = mongoTemplate.count(query, tClass);
        log.info("统计sql: {}", query);
        int offset = (dto.getCurrentPageNum() - 1) * dto.getSize();
        # 分页条件处理
        SkipOperation skipOperation = Aggregation.skip(offset);
        LimitOperation limitOperation = Aggregation.limit(dto.getSize());
        Aggregation aggregation = null;
        List<AggregationOperation> list = new ArrayList<>();
        if(condSortParam != null) {
            list.add(matchOperation);
            # 此处为【添加字段】条件集合
            condSortParam.getAddFieldsOperations().forEach(s-> list.add(s));
            if(condSortParam.getSortOperation() != null) {
                list.add(condSortParam.getSortOperation());
            }
            list.add(skipOperation);
            list.add(limitOperation);
            aggregation = Aggregation.newAggregation(list);
        }
        log.info("分页查询sql: {}", aggregation);
        List<T> results = mongoTemplate.aggregate(aggregation, tClass, tClass).getMappedResults();
        PageVO<T> pageVO = new PageVO<T>();
        pageVO.setTotalNum(count);
        pageVO.setResults(results);
        return pageVO;
    }
    /*
     * 处理查询条件
     */
    private static Criteria handleCriteria(PageRequestDTO dto) {
        List<ParamDTO> params = dto.getParams();
        Criteria criteria = new Criteria();
        if(CollUtil.isEmpty(params)) return criteria;
        params.forEach(param -> {
            String operator = param.getOperator();
            switch (operator) {
                case "eq" -> criteria.and(param.getField()).is(param.getFieldValue());
                case "like" -> criteria.and(param.getField()).regex(Pattern.compile("^.*" + param.getFieldValue()
                        + ".*$", Pattern.CASE_INSENSITIVE));
                case "le" -> criteria.and(param.getField()).lt(param.getFieldValue());
                case "ge" -> criteria.and(param.getField()).gt(param.getFieldValue());
                case "in" -> {
                    List<String> values = null;
                    if (param.getFieldValue() instanceof JSONArray) {
                        JSON.parseArray(param.getFieldValue().toString(), String.class);
                        criteria.and(param.getField()).in(values);
                    }else if(param.getFieldValue() instanceof String){
                        criteria.and(param.getField()).in(param.getFieldValue().toString().split(StrUtil.COMMA));
                    }
                }
                case "between" -> {
                    if (param.getFieldValue() instanceof JSONArray) {
                        List<Object> list = JSON.parseArray(param.getFieldValue().toString(), Object.class);
                        if (CollUtil.isNotEmpty(list)) {
                            criteria.and(param.getField()).gte(list.get(0)).lte(list.get(1));
                        }
                    }
                }
                default -> {
                }
            }
        });
        return criteria;
    }

三、对二中condSortParam参数进行加工后的程序

  • AggregationOperation加工方法
    注意:此处使用switch应对业务场景创建,不同case的处理operation的复杂度不同
    较复杂case:添加了两个字段的判断 代码case上已标注
    简单case:只添加了一个字段的判断 代码case上已标注
java 复制代码
/*
 * 获取聚合函数所需参数
 */
public static DataToolUtil.CondSortParam createDCondSortParamByPageType(String pageType) {
     String [] codes;
     String addSortFieldName = "statusOrder";
     String sortFieldName = "status";
     AtomicInteger level = new AtomicInteger();
     SortOperation sortOperation;
     switch (pageType) {
    	 # 简单case 
         case D_STATUS.TYPE_APPLY:
             codes = new String[]{D_STATUS.APPLY_REJECT.getCode(), D_STATUS.AUDITED_PRINTED.getCode(), D_STATUS.AUDITED.getCode()
                     , D_STATUS.APPLY.getCode(), D_STATUS.APPLY_REVOKE.getCode(), D_STATUS.SUBMIT.getCode()
                     , D_STATUS.REPORT_REJECT.getCode(), D_STATUS.REVOKE_AUDITED.getCode(), D_STATUS.REVOKE.getCode()
                     , D_STATUS.REPORT_DRAFT.getCode(), D_STATUS.DATA_DESTRY.getCode()
             };
             sortOperation = Aggregation.sort(Sort.Direction.DESC, addSortFieldName, "applyTime");
             return new DataToolUtil.CondSortParam.Builder()
                     .addFieldOperation(createCondSortParamByPageType(sortFieldName, codes, level, addSortFieldName))
                     .addSortOperation(sortOperation)
                     .build();
         # 简单case
         case D_STATUS.TYPE_REPORT:
             codes = new String[]{D_STATUS.REPORT_REJECT.getCode(), D_STATUS.REVOKE.getCode(), D_STATUS.REPORT_DRAFT.getCode()
                     , D_STATUS.APPLY.getCode(), D_STATUS.APPLY_REJECT.getCode()
             };
             sortOperation = Aggregation.sort(Sort.Direction.DESC, addSortFieldName, "applyTime");
             return new DataToolUtil.CondSortParam.Builder()
                     .addFieldOperation(createCondSortParamByPageType(sortFieldName, codes, level, addSortFieldName))
                     .addSortOperation(sortOperation)
                     .build();
         # 复杂case, 添加了两个AddSortFieldName
         case D_STATUS.TYPE_AUDIT:
             DataToolUtil.RelationWrapper statusWrapper = DataToolUtil.RelationWrapper.builder()
                     .addSortFieldName(addSortFieldName).sortFieldname(sortFieldName).build();
             DataToolUtil.RelationWrapper pati..Wrapper = DataToolUtil.RelationWrapper.builder()
                     .addSortFieldName("pati....ypeIdOrder").sortFieldname("pati....ypeId").build();
             codes = new String[]{D_STATUS.REVOKE.getCode(), D_STATUS.SUBMIT.getCode(), D_STATUS.AUDITED.getCode(), D_STATUS.AUDITED_PRINTED.getCode()};
             sortOperation = Aggregation.sort(Sort.Direction.DESC, pati..Wrapper.getAddSortFieldName()).and(Sort.by(Sort.Direction.DESC, statusWrapper.getAddSortFieldName(), "app...ime"));
             return new DataToolUtil.CondSortParam.Builder()
                     .addFieldOperation(createCondSortParamByPageType(statusWrapper.getSortFieldname(), codes, level, statusWrapper.getAddSortFieldName()))
                     .addFieldOperation(createCondSortParamByPageType(pati..Wrapper.getSortFieldname(), new String[]{PATIENT_TYPE.EMERGENCY.getCode()}, level, pati..Wrapper.getAddSortFieldName()))
                     .addSortOperation(sortOperation)
                     .build();
         default:
             return null;
     }
 }
/**
 * 分页排序公共参数。
 * 带条件排序字段与排序字段的排列顺序
 */
@Data
@Builder
public static class CondSortParam{
   /** 提供的AggregationOperation */
   List<AddFieldsOperation> addFieldsOperations;

   /** 组合排序字段。如 Aggregation.sort(Direction.DESC, "sortOrder", "applyTime") */
   SortOperation sortOperation;

   public static class Builder {
       private CondSortParam condSortParam = CondSortParam.builder().build();

       public Builder() {
           this.condSortParam.addFieldsOperations = new ArrayList<>();
       }

       public Builder addFieldOperation(AddFieldsOperation addFieldsOperation) {
           this.condSortParam.addFieldsOperations.add(addFieldsOperation);
           return this;
       }

       public Builder addSortOperation(SortOperation sortOperation) {
           this.condSortParam.sortOperation = sortOperation;
           return this;
       }

       public CondSortParam build() {
           return this.condSortParam;
       }
   }

}
/*
 * 绑定排序时需要条件判断而添加的字段名称与原字段名称
 */
 @Data
 @lombok.Builder
 public static class RelationWrapper {
	 /** 增加的字段,拍寻优先级使用 */
     private String addSortFieldName;
	 /** 需要被排序的字段, 条件判断使用 */
     private String sortFieldname;
 }
  • 入口调用方法
java 复制代码
@Operation(summary = "列表查询", parameters = {
       @Parameter(name = "pageRequest", description = "...", required = true)
})
@PostMapping("queryPage")
public CommonJsonResponseVO queryPage(@RequestBody PageRequestDTO pageRequest) {
	...
    PageVO<RemoteDiagnosis> pageVO = DataToolUtil.pagination(pageRequest, RemoteDiagnosis.class, mongoTemplate, Status.createDiagCondSortParamByPageType(pageRequest.getPageType()));
    return CommonJsonResponseVO.success(PageUtil.toPage(pageVO.getResults(), pageVO.getTotalNum()));
}

总结

  • 复杂排序的完成需要从简单的排序入手。逐渐增加复杂度将有路可循。
  • AI的正确使用会提高成功效率。只是凭借以往的查询方式(如百度查询等)无法深入挖掘一个工具的使用方法,比较困难。
  • 对象化的参数会对复杂的排序提高可读性、易用性。如:RelationWrapper 对参数进行抽象
相关推荐
Qinana1 小时前
第一次用向量数据库!手搓《天龙八部》RAG助手,让AI真正“懂”你
前端·数据库·后端
DolphinDB18 小时前
集成 Prometheus 与 DolphinDB 规则引擎,构建敏捷监控解决方案
数据库
IvorySQL19 小时前
PostgreSQL 技术日报 (3月10日)|IIoT 性能瓶颈与内核优化新讨论
数据库·postgresql·开源
DBA小马哥1 天前
时序数据库是什么?能源行业国产化替换的入门必看
数据库·时序数据库
后端AI实验室1 天前
我把一个生产Bug的排查过程,交给AI处理——20分钟后我关掉了它
java·ai
爱可生开源社区1 天前
某马来西亚游戏公司如何从 SQL Server 迁移至 OceanBase?
数据库
JohnCHsu1 天前
性能干翻235B,单卡私有化部署OpenClaw
ai·agent·llama.cpp·openclaw
牧马人win1 天前
Cursor 四种交互模式
ai·cursor
小瓦码J码1 天前
PostgreSQL表名超长踩坑记
数据库·postgresql
yhyyht1 天前
InfluxDB入门记录(三)flux-dsl
数据库·后端