You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data MongoDB:如何将Document转换回Criteria(含复杂场景)

解决方案:将处理后的Document转回Criteria(适配复杂多操作符场景)

这个问题确实戳中了Spring Data MongoDB的一个小痛点——它原生只支持把Criteria转成Document,反向的转换并没有提供现成API。不过咱们可以通过手动解析BSON文档的结构,递归构建Criteria对象来解决,就算是包含$and、$or、$gt这类多操作符的复杂场景也能搞定。

核心思路:递归解析BSON操作符

MongoDB的查询操作符在Document里都是以键值对形式存在的,我们可以遍历文档的每一个条目,根据操作符的类型(逻辑操作符如$and,字段操作符如$gt)来对应构建Criteria的条件:

  • 普通键值对:直接用Criteria.where(key).is(value)
  • 字段级操作符(比如$gt、$in):调用Criteria对应的方法(.gt()、.in())
  • 逻辑操作符(比如$and、$or):递归处理内部的条件数组,再用.andOperator()或.orOperator()组合起来

实现转换工具类

下面是一个可以处理大多数复杂场景的工具类示例,你可以根据自己的需求扩展更多操作符:

import org.springframework.data.mongodb.core.query.Criteria;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DocumentToCriteriaConverter {

    public static Criteria convert(Document document) {
        if (document == null || document.isEmpty()) {
            return new Criteria();
        }

        List<Criteria> criteriaList = new ArrayList<>();

        for (Map.Entry<String, Object> entry : document.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            // 处理逻辑操作符:$and、$or、$not等
            if (key.startsWith("$")) {
                switch (key) {
                    case "$and":
                        List<Criteria> andCriterias = new ArrayList<>();
                        for (Object obj : (List<?>) value) {
                            andCriterias.add(convert((Document) obj));
                        }
                        criteriaList.add(new Criteria().andOperator(andCriterias.toArray(new Criteria[0])));
                        break;
                    case "$or":
                        List<Criteria> orCriterias = new ArrayList<>();
                        for (Object obj : (List<?>) value) {
                            orCriterias.add(convert((Document) obj));
                        }
                        criteriaList.add(new Criteria().orOperator(orCriterias.toArray(new Criteria[0])));
                        break;
                    case "$not":
                        criteriaList.add(convert((Document) value).not());
                        break;
                    // 可以根据需要扩展$nor等其他逻辑操作符
                    default:
                        throw new IllegalArgumentException("不支持的逻辑操作符: " + key);
                }
            } else {
                // 处理字段级操作符:$gt、$lt、$in等
                if (value instanceof Document) {
                    Document fieldDoc = (Document) value;
                    Criteria fieldCriteria = Criteria.where(key);
                    for (Map.Entry<String, Object> fieldEntry : fieldDoc.entrySet()) {
                        String operator = fieldEntry.getKey();
                        Object fieldValue = fieldEntry.getValue();
                        switch (operator) {
                            case "$gt":
                                fieldCriteria.gt(fieldValue);
                                break;
                            case "$lt":
                                fieldCriteria.lt(fieldValue);
                                break;
                            case "$gte":
                                fieldCriteria.gte(fieldValue);
                                break;
                            case "$lte":
                                fieldCriteria.lte(fieldValue);
                                break;
                            case "$in":
                                fieldCriteria.in((List<?>) fieldValue);
                                break;
                            case "$nin":
                                fieldCriteria.nin((List<?>) fieldValue);
                                break;
                            case "$eq":
                                fieldCriteria.is(fieldValue);
                                break;
                            case "$ne":
                                fieldCriteria.ne(fieldValue);
                                break;
                            // 可以扩展$regex、$exists等字段操作符
                            default:
                                throw new IllegalArgumentException("不支持的字段操作符: " + operator);
                        }
                    }
                    criteriaList.add(fieldCriteria);
                } else {
                    // 普通等值条件
                    criteriaList.add(Criteria.where(key).is(value));
                }
            }
        }

        // 多个条件默认用AND组合
        if (criteriaList.size() == 1) {
            return criteriaList.get(0);
        } else {
            return new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));
        }
    }
}

使用示例

假设你有一个处理后的Document:

Document processedDoc = new Document("$and", List.of(
    new Document("age", new Document("$gt", 18).append("$lt", 30)),
    new Document("status", new Document("$in", List.of("ACTIVE", "PENDING"))),
    new Document("$or", List.of(
        new Document("city", "Beijing"),
        new Document("city", "Shanghai")
    ))
));

只需要调用工具类的转换方法,就能得到对应的Criteria:

Criteria criteria = DocumentToCriteriaConverter.convert(processedDoc);
// 此时的criteria和你原生用API构建的复杂条件完全等价

注意事项

  • 这个工具类可以根据你的业务需求扩展更多操作符,比如$elemMatch、$regex这类特殊场景
  • 对于嵌套层级极深的BSON结构,需要额外处理内部的数组和嵌套文档逻辑
  • 转换后建议做测试验证,确保查询效果和原Criteria完全一致

内容的提问来源于stack exchange,提问作者user2137817

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:37:32