SpringBoot MongoTemplate使用详解

发布于:2024-06-29 ⋅ 阅读:(11) ⋅ 点赞:(0)

前面文章讲了 SpringBoot整合MongoDB JPA使用:https://blog.csdn.net/qq_42402854/article/details/139973336

在项目中,通常会 JPA语法与 MongoTemplate两者结合使用,特别是针对复杂动态条件查询时,MongoTemplate更加友好。

SpringBoot整合 MongoDB和前面文章一样,使用 @Autowired注入 MongoTemplate就可以直接使用。

一、增删改

1、插入文档

  • insert插入文档时,如果插入数据的主键已经存在,则会抛 DuplicateKeyException 键重复异常,不保存当前数据。支持批量。
  • save插入文档时,如果插入数据的主键已经存在,则会更新当前数据,如果不存在则会保存当前数据。不支持批量。JPA语法支持。
    @Test
    public void testInsert() {
        List<DeviceGpsDO> list = new ArrayList<>();
        DeviceGpsDO deviceGpsDO = new DeviceGpsDO();
        deviceGpsDO.setDeviceName("插入数据");
        deviceGpsDO.setSatelliteTime(new Date());
        deviceGpsDO.setLocation(new GeoJsonPoint(108.552500, 34.322700));
        deviceGpsDO.setLongitude(108.552500);
        deviceGpsDO.setLatitude(34.322700);
        list.add(deviceGpsDO);

        //  插入一个
        deviceGpsDO.setId("100");
        mongoTemplate.insert(deviceGpsDO);
        deviceGpsDO.setId(null);
        mongoTemplate.insert(deviceGpsDO, "mongoTemplate_insert");
        deviceGpsDO.setId(null);
        mongoTemplate.insert(deviceGpsDO, "mongoTemplate_insert");
        //  根据集合名称插入多个
        deviceGpsDO.setId(null);
        mongoTemplate.insert(list, DeviceGpsDO.class);
        deviceGpsDO.setId(null);
        mongoTemplate.insert(list, "mongoTemplate_insert");
        deviceGpsDO.setId(null);
        mongoTemplate.insertAll(list);

         保存或者更新一个
        deviceGpsDO.setId("101");
        mongoTemplate.save(deviceGpsDO);
        mongoTemplate.save(deviceGpsDO, "mongoTemplate_save");
        deviceGpsDO.setSpeed(5.5F);
        mongoTemplate.save(deviceGpsDO, "mongoTemplate_save");
        // 保存或者更新多个不支持。保存信息:Couldn't find PersistentEntity for type java.lang.Object!
        //mongoTemplate.save(list);  
        //mongoTemplate.save(list, "mongoTemplate_save");
    }

2、更新文档

    @Test
    public void testUpdate() {
        Query query = Query.query(Criteria.where("_id").is("100"));
        Update update = Update.update("device_name", "更新数据")
                .set("vin_no", "vin_no111")
                .set("speed", 11)
                .set("speed2", "2-1"); // 字段不存在则新增

        //  更新一条数据
        mongoTemplate.updateFirst(query, update, DeviceGpsDO.class);
        mongoTemplate.updateFirst(query, update, "mongoTemplate_save");
        mongoTemplate.updateFirst(query, update, DeviceGpsDO.class, "mongoTemplate_save");

        //  更新多条数据
        Query query2 = Query.query(Criteria.where("speed").gte(2));
        Update update2 = Update.update("device_name", "更新数据")
                .set("vin_no", "vin_no222")
                .set("speed", 22);
        mongoTemplate.updateMulti(query2, update2, DeviceGpsDO.class);
        mongoTemplate.updateMulti(query2, update2, "mongoTemplate_insert");
        mongoTemplate.updateMulti(query2, update2, DeviceGpsDO.class, "mongoTemplate_save");

        //  更新数据,如果数据不存在就新增
        mongoTemplate.upsert(query, update, DeviceGpsDO.class);
        mongoTemplate.upsert(query, update, "mongoTemplate_save");
        mongoTemplate.upsert(query2, update2, DeviceGpsDO.class, "mongoTemplate_update");
    }

3、删除文档

    @Test
    public void testSave(){
        DeviceGpsDO deviceGpsDO = new DeviceGpsDO();
        deviceGpsDO.setId("100");

        Query query = Query.query(Criteria.where("_id").in("667ad10d25e5aa38d6126339","667c33fc68e19b549ee24bfc"));
        //  根据条件删除
        mongoTemplate.remove(deviceGpsDO);
        mongoTemplate.remove(deviceGpsDO, "mongoTemplate_save");
        //  根据条件删除(可删除多条)
        mongoTemplate.remove(query, "mongoTemplate_insert");
        mongoTemplate.remove(query, DeviceGpsDO.class);
        mongoTemplate.remove(query, DeviceGpsDO.class,"mongoTemplate_insert");
    }

二、查询详解

使用 Query构建查询条件。

  • Criteria对象,用来封装所有的查询条件。
  • Query对象,用来封装所有的查询条件对象。

创建Criteria对象:

  • 方式一:直接 new对象 Criteria criteria = new Criteria();
  • 方式二:通过 Criteria.where()静态方法。比如:Criteria.where(“属性名”).is(“值”).and(“属性名”).gte(“值”)进行查询。

注意: Criteria的两种方式不能混合使用,否则不生效。

创建Query对象:

Query query = new Query(criteria);

1、精确查询

    @Test
    public void testQuery1(){
        //精确查询
        Criteria criteria = new Criteria();
        criteria.and("id").is("101");
        Query query = new Query(criteria);
        // { "_id" : "101"}
        DeviceGpsDO deviceGpsDO1 = mongoTemplate.findOne(query, DeviceGpsDO.class);
        DeviceGpsDO deviceGpsDO2 = mongoTemplate.findOne(query, DeviceGpsDO.class, "mongoTemplate_save");
    }

2、or查询

在 MongoTemplate 中 or 是用 orOperator表示的。

    @Test
    public void testQuery2(){
        //or查询
        Criteria criteria = new Criteria();
        criteria.and("_id").is("101").orOperator(
                Criteria.where("longitude").is(108.552500)
        );
        Query query = new Query(criteria);
        // { "_id" : "101", "$or" : [{ "longitude" : 108.5525}]}
        List<DeviceGpsDO> deviceGpsDO1List = mongoTemplate.find(query, DeviceGpsDO.class);
        List<DeviceGpsDO> deviceGpsDO2List = mongoTemplate.find(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

3、范围查询

    @Test
    public void testQuery3(){
        //范围查询
        Criteria criteria = Criteria.where("speed").gte(1).lte(30).and("longitude").is(108.552500);
        Query query = new Query(criteria);
        // { "speed" : { "$gte" : 1, "$lte" : 30}, "longitude" : 108.5525}
        List<DeviceGpsDO> deviceGpsDO2List = mongoTemplate.find(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

4、时间范围查询

    @Test
    public void testQuery4(){
        //时间范围查询。 不用考虑时差,正常时间类型条件即可。
        Criteria criteria = Criteria.where("update_time")
                .gte(LocalDateTimeUtil.parse("2024-06-27 15:00:00", DatePattern.NORM_DATETIME_PATTERN))
                .lte(LocalDateTimeUtil.parse("2024-06-27 23:59:59", DatePattern.NORM_DATETIME_PATTERN));
        Query query = new Query(criteria);
        // { "update_time" : { "$gte" : { "$date" : "2024-06-27T07:00:00Z"}, "$lte" : { "$date" : "2024-06-27T15:59:59Z"}}}
        List<DeviceGpsDO> deviceGpsDO2List = mongoTemplate.find(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

5、模糊查询

模糊查询以 【^】开始 以【$】结束 【.*】相当于Mysql中的【%】。

    @Test
    public void testQuery5() {
        //模糊查询/正则查询
        String deviceName = "数据";
        Pattern pattern = Pattern.compile("^.*" + deviceName + ".*$", Pattern.CASE_INSENSITIVE);
        Criteria criteria = Criteria.where("device_name").regex(pattern);
        Query query = new Query(criteria);
        // { "device_name" : { "$regularExpression" : { "pattern" : "^.*数据.*$", "options" : "i"}}}
        List<DeviceGpsDO> deviceGpsDO2List = mongoTemplate.find(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

6、排序查询

Sort对象通过参数 direction枚举指定排序方向,sortField 为排序字段。

    @Test
    public void testQuery6() {
        //排序查询
        String deviceName = "数据";
        Pattern pattern = Pattern.compile("^.*" + deviceName + ".*$", Pattern.CASE_INSENSITIVE);
        Criteria criteria = Criteria.where("device_name").regex(pattern);
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Direction.DESC, "update_time"));
        // {"find": "mongoTemplate_insert", "filter": {"device_name": {"$regularExpression": {"pattern": "^.*数据.*$", "options": "i"}}}, "sort": {"update_time": -1}, "$db": "ws_sb_local", "lsid": {"id": {"$binary": {"base64": "fUndebK2RXiOro31pR0F5w==", "subType": "04"}}}}
        List<DeviceGpsDO> deviceGpsDO2List = mongoTemplate.find(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

7、总数查询

    @Test
    public void testQuery7() {
        //总数查询
        String deviceName = "插入";
        Pattern pattern = Pattern.compile("^.*" + deviceName + ".*$", Pattern.CASE_INSENSITIVE);
        Criteria criteria = Criteria.where("device_name").regex(pattern);
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Direction.DESC, "update_time"));
        // {"aggregate": "mongoTemplate_insert", "pipeline": [{"$match": {"device_name": {"$regularExpression": {"pattern": "^.*插入.*$", "options": "i"}}}}, {"$group": {"_id": 1, "n": {"$sum": 1}}}], "cursor": {}, "$db": "ws_sb_local", "lsid": {"id": {"$binary": {"base64": "64gumgsaQMCw1vUDQEIKlg==", "subType": "04"}}}}
        long count1 = mongoTemplate.count(query, DeviceGpsDO.class, "mongoTemplate_insert");
    }

8、分页查询

在 MongoTemplate 中处理分页方式有三种:

  • PageRequest分页 - 推荐使用
  • limit限定条件查询
  • skip跳过指定数量的查询
    @Test
    public void testQuery8() {
        //分页查询推荐:PageRequest
        String deviceName = "数据";
        Pattern pattern = Pattern.compile("^.*" + deviceName + ".*$", Pattern.CASE_INSENSITIVE);
        Criteria criteria = Criteria.where("device_name").regex(pattern);
        Query query = new Query(criteria);
        // 总数量
        long total = mongoTemplate.count(query, DeviceGpsDO.class);
        // MongoDB 默认第一页是0, 公式为:(currentPage - 1) * pageSize, pageSize
        int currentPage = 3;
        int pageSize = 10;
        Pageable pageable = PageRequest.of(currentPage - 1, pageSize, Sort.by(Sort.Direction.DESC, "update_time"));
        query.with(pageable);
        // 当前页数量
        long currentPageTotal = mongoTemplate.count(query, DeviceGpsDO.class);
        List<DeviceGpsDO> doList = this.mongoTemplate.find(query , DeviceGpsDO.class);

        log.info("currentPage = {}", currentPage);
        log.info("pageSize = {}", pageSize);
        log.info("currentPageTotal = {}", currentPageTotal);
        log.info("total = {}", total);
        log.info("totalPages = {}", (int) Math.ceil((double) total / (double) pageSize));
        log.info("doList = {}", doList);
    }

– 求知若饥,虚心若愚。