前面文章讲了 SpringBoot整合MongoDB JPA使用:/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 !
//(list);
//(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();
- 方式二:通过 ()静态方法。比如:(“属性名”).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);
}
– 求知若饥,虚心若愚。