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 对参数进行抽象
相关推荐
AlfredZhao16 分钟前
APEX实战第1篇:本地部署拥有AI能力的APEX
ai·apex·23ai·deepseek·ords
夜泉_ly2 小时前
MySQL -安装与初识
数据库·mysql
weixin_438335403 小时前
springboot多实例部署时,@Scheduled注释的方法重复执行
springboot
qq_529835353 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
月光水岸New6 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6756 小时前
数据库基础1
数据库
我爱松子鱼6 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser7 小时前
【SQL】多表查询案例
数据库·sql
Galeoto7 小时前
how to export a table in sqlite, and import into another
数据库·sqlite