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 对参数进行抽象
相关推荐
Python私教1 分钟前
Python国产新 ORM 框架 fastzdp_sqlmodel 快速入门教程
java·数据库·python
孟章豪3 分钟前
SQL Server全方位指南:从入门到高级详解
数据库
数分大拿的Statham5 分钟前
PostgreSQL中的regexp_split_to_table函数详解,拆分字段为多行
大数据·数据库·postgresql·数据分析·数据清洗
mqiqe5 分钟前
PostgreSQL主备环境配置
数据库·postgresql
mqiqe8 分钟前
PostgreSQL 容器安装
数据库·postgresql
小光学长37 分钟前
基于vue框架的宠物寻回小程序8g7el(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库
一叶飘零_sweeeet39 分钟前
深入理解 MySQL MVCC:多版本并发控制的核心机制
数据库·mysql
中文很快乐1 小时前
springboot结合p6spy进行SQL监控
java·数据库·sql
小电玩1 小时前
谈谈你对Spring的理解
java·数据库·spring
小光学长1 小时前
基于flask+vue框架的传染病防控酒店信息系统zvt93(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库