MongoTemplate查询工具类,大家都来试试吧

1 代码

1.1 查询条件构建基础类

设计用来支持流式查询,以及增强语义化的一些类

package xyz.yq56.mongo.entity.query;

import java.util.HashMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 精确查询基础类,理论上下面范围和排序也可以用这个代替,但是语义很差
 * @author yiqiang
 */
public class ChainMap extends HashMap<String, Object> {
    public static ChainMap build() {
        return new ChainMap();
    }

    public ChainMap add(String key, Object value) {
        this.put(key, value);
        return this;
    }

    @Override
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            return "";
        }
    }
}


package xyz.yq56.mongo.entity.query;

import java.util.Arrays;
import java.util.HashMap;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 排序基础类
 * @author yi qiang
 * @date 2022/8/7 16:23
 */
public class ChainOrder extends HashMap<String, String> {
    public static final String DESC = "DESC";
    public static final String ASC = "ASC";

    public static ChainOrder build() {
        return new ChainOrder();
    }

    /**
     * 添加排序
     *
     * @param key   排序字段
     * @param value 顺序: asc or desc
     * @return 排序封装类
     */
    public ChainOrder add(String key, String value) {
        if (!Arrays.asList(DESC, ASC).contains(value.toUpperCase())) {
            throw new IllegalArgumentException();
        }
        this.put(key, value.toUpperCase());
        return this;
    }

    @Override
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            return "";
        }
    }
}

package xyz.yq56.mongo.entity.query;

import java.util.HashMap;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 范围查询基础类
 * @author yi qiang
 * @date 2022/8/7 15:10
 */
public class ChainRange extends HashMap<String, ChainRange.Range> {

    public static ChainRange build() {
        return new ChainRange();
    }


    public ChainRange add(String key, Range value) {
        this.put(key, value);
        return this;
    }

    @Data
    @Accessors(chain = true)
    public static class Range {
        //左边是否是开区间,默认是闭区间
        private boolean leftOpen;
        //右边是否是开区间,默认是闭区间
        private boolean rightOpen;
        //左边值
        private Object left;
        //右边值
        private Object right;
    }

    @Override
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            return "";
        }
    }
}


1.2 查询条件构建类MongoParam

设计出来其实主要功能就是build方法来构建Query对象,其内部封装了多条件判空,offset计算以及多条件排序等功能.理论上,只要创建好MongoParam,然后调用build方法即可得到想要的查询结果
另外也贴心的准备了buildForCount方法,用来给到count方法使用

package xyz.yq56.mongo.entity.query;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * @author yiqiang
 */
@Accessors(chain = true)
@Data
@SuppressWarnings("all")
public class MongoParam {

    /**
     * 相等的字段
     */
    ChainMap eqFields;
    /**
     * 范围查询字段
     */
    ChainRange rangeFields;
    /**
     * 排序字段
     */
    ChainOrder orderFields;
    /**
     * 偏移量
     */
    Long offset;
    /**
     * 页码
     */
    Long page;
    /**
     * 页面大小
     */
    Integer size;

    /**
     * 构建查询条件
     *
     * @return 返回MongoTemplate所需查询条件
     */
    public Query build() {
        Query query = new Query();
        query.addCriteria(createCriteria());
        withOrder(query);
        withPage(query);
        return query;
    }

    /**
     * 为计数构建Query,不需要排序和分页等字段逻辑
     * <br> 已浅拷贝对象,不会影响build()结果
     *
     * @return 查询对象
     */
    public Query buildForCount() {
        MongoParam params = new MongoParam();
        BeanUtils.copyProperties(this, params);
        params.orderFields = null;
        params.offset = null;
        params.page = null;
        params.size = null;
        return params.build();
    }

    /**
     * 仅仅只会给query添加分页相关属性,如skip和limit
     *
     * @param query 查询
     */
    public Query withPage(Query query) {
        if (query == null) {
            return null;
        }
        if (size != null) {
            query.limit(size);
            if (page != null) {
                query.skip((Math.max(page - 1, 0) * size));
            }
        }
        //优先offset
        if (offset != null) {
            query.skip(offset);
        }
        return query;
    }

    /**
     * 仅仅只会给query添加排序相关属性
     *
     * @param query 查询
     */
    public Query withOrder(Query query) {
        if (query == null) {
            return null;
        }
        //排序Map不为空,那么构建排序字段
        if (orderFields != null && orderFields.size() > 0) {
            List<Sort.Order> orderList = new ArrayList<>();
            //key是待排序字段;value是DESC或ASC字符串,大小写不敏感;
            orderFields.forEach((key, value) -> orderList.add(new Sort.Order(Sort.Direction.valueOf(value), key)));
            query.with(Sort.by(orderList));
        }
        return query;
    }

    /**
     * 获取到查询相关属性,包含精确查询和范围查询
     *
     * @return 基准
     */
    public Criteria createCriteria() {
        Criteria criteria = new Criteria();
        //精确匹配字段条件构建
        if (eqFields != null && eqFields.size() > 0) {
            eqFields.forEach((key, value) -> {
                if (value != null) {
                    if (value instanceof String && ((String) value).length() <= 0) {
                        return;
                    }
                    if (value instanceof Collection && ((Collection) value).isEmpty()) {
                        return;
                    }
                    if (value instanceof Map && ((Map) value).isEmpty()) {
                        return;
                    }
                    criteria.and(key).is(value);
                }
            });
        }

        //范围查询
        if (rangeFields != null && rangeFields.size() > 0) {
            rangeFields.forEach((key, value) -> {
                Criteria keyCriteria = criteria.and(key);
                Criteria leftCriteria = leftCriteria(keyCriteria, value);
                //如果左边条件不存在,那就直接检查右边条件
                if (leftCriteria != null) {
                    rightCriteria(leftCriteria, value);
                } else {
                    rightCriteria(keyCriteria, value);
                }
            });
        }
        return criteria;
    }

    private Criteria leftCriteria(Criteria criteria, ChainRange.Range range) {
        if (range.getLeft() != null) {
            if (range.isLeftOpen()) {
                return criteria.gt(range.getLeft());
            } else {
                return criteria.gte(range.getLeft());
            }
        }
        return null;
    }

    private Criteria rightCriteria(Criteria criteria, ChainRange.Range range) {
        if (range.getRight() != null) {
            if (range.isRightOpen()) {
                return criteria.lt(range.getRight());
            } else {
                return criteria.lte(range.getRight());
            }
        }
        return null;
    }

    @Override
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            return "";
        }
    }
}

1.3 查询工具类

package xyz.yq56.mongo.util;

import java.util.List;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;

import xyz.yq56.mongo.entity.query.MongoParam;

/**
 * @author yi qiang
 * @date 2022/8/7 4:43
 */
public class MongoUtil {

    private MongoUtil() {
    }


    public static <T> List<T> list(MongoTemplate mongoTemplate, MongoParam mongoParam, Class<T> zClass) {
        return mongoTemplate.find(mongoParam.build(), zClass);
    }
    
}

2 使用示例

2.1 测试代码

@Repository
@Slf4j
public class RoomBonusDailyDataDaoMongoImpl {

    @Autowired
    MongoTemplate mongoTemplate;

    public List<RoomBonusDailyData> test() {
        Date left = new Date(System.currentTimeMillis() - (60 * 1000 * 60 * 24) * 10);

        MongoParam mongoParam = new MongoParam()
                .setEqFields(ChainMap.build()
                        .add("uid", "752")
                        .add("roomId", "2")
                )
                .setRangeFields(ChainRange.build()
                        .add("updateTime", new ChainRange.Range().setLeft(left))
                        .add("type", new ChainRange.Range().setLeft(1).setRight(2))
                )
                .setOrderFields(ChainOrder.build()
                        .add("updateTime", "ASC")
                        .add("uid", "DESC"))
                .setPage(1L)
                .setSize(10);

        System.out.println(mongoParam);
       
        return MongoUtil.list(mongoTemplate, mongoParam, RoomBonusDailyData.class);
    }
}

2.2 输出结果

从发送的command可以看到所有的条件都已生效

{
  "eqFields" : {
    "uid" : "752",
    "roomId" : "2"
  },
  "rangeFields" : {
    "updateTime" : {
      "leftOpen" : false,
      "rightOpen" : false,
      "left" : 1659021724377,
      "right" : null
    },
    "type" : {
      "leftOpen" : false,
      "rightOpen" : false,
      "left" : 1,
      "right" : 2
    }
  },
  "orderFields" : {
    "uid" : "DESC",
    "updateTime" : "ASC"
  },
  "offset" : null,
  "page" : 1,
  "size" : 10
}
2022-08-07 23:22:04.440 DEBUG 13152 --- [           main] o.s.data.mongodb.core.MongoTemplate      : find using query: { "uid" : "752", "roomId" : "2", "updateTime" : { "$gte" : { "$date" : 1659021724377}}, "type" : { "$gte" : 1, "$lte" : 2}} fields: Document{{}} for class: class xyz.yq56.mongo.entity.RoomBonusDailyData in collection: roomBonusDailyData
2022-08-07 23:22:04.466  INFO 13152 --- [           main] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:269}] to localhost:27017
2022-08-07 23:22:04.478 DEBUG 13152 --- [           main] org.mongodb.driver.protocol.command      : Sending command '{"find": "roomBonusDailyData", "filter": {"uid": "752", "roomId": "2", "updateTime": {"$gte": {"$date": "2022-07-28T15:22:04.377Z"}}, "type": {"$gte": 1, "$lte": 2}}, "sort": {"uid": -1, "updateTime": 1}, "limit": 10, "$db": "test"}' with request id 6 to database test on connection [connectionId{localValue:2, serverValue:269}] to server localhost:27017
2022-08-07 23:22:04.478 DEBUG 13152 --- [           main] org.mongodb.driver.protocol.command      : Execution of command with request id 6 completed successfully in 4.66 ms on connection [connectionId{localValue:2, serverValue:269}] to server localhost:27017
[RoomBonusDailyData(id=2-2-20220801, type=2, roomId=2, uid=752, region=6, value=529, weekStartDate=20220801, updateTime=Mon Aug 01 22:47:18 CST 2022)]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值