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 对参数进行抽象
相关推荐
在努力的前端小白4 分钟前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
未来之窗软件服务6 分钟前
自建知识库,向量数据库 (九)之 量化前奏分词服务——仙盟创梦IDE
数据库·仙盟创梦ide·东方仙盟·自建ai·ai分词
冒泡的肥皂3 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.4 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
zhayujie5 小时前
RAG优化实战 - LinkAI智能体平台的知识库升级之路
ai·大模型·agent·知识库·rag
造梦师阿鹏6 小时前
004.从 API 裸调到 LangChain
经验分享·ai·大模型·ai技术·大模型应用开发
anghost1506 小时前
基于单片机的智能声控窗帘
单片机·嵌入式硬件·mongodb
薛晓刚7 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队7 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光8 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql