基于 MongoTemplate 实现MongoDB的复杂查询
MongoDB是典型的非关系型数据库,但是它的功能越来越复杂,很多项目中,我们为了快速拓展,甚至直接使用Mongo 来替代传统DB做数据持久化。
虽然MongoDB在支持具体业务时没有问题,但是由于它是文档型数据库,拥有一套独立的语法,不再支持传统的SQL。
开发人员发现在实际开发过程中,由于语法问题,在处理复杂的业务查询时,不知该如何下手,使不上劲。
在这里我总结了一下接触到的使用场景:
如果是简单的业务,那么我们直接使用spring JPA来实现就可以,比如这些操作:
1、创建
2、删除
3、修改
4、简单的查询
因为这些语句的逻辑往往不是很复杂,JPA完全可以胜任,而且还清晰直观。
如果是复杂的场景,我们就使用MongoTemplate 来组织条件逻辑:
假设背景是有张Student 表,结构如下:
我们已经预先插入了下边的数据:

(1)先来一个简单的
单条件查询:
1 private void simpleInQuery() {
2 Query query = new Query();
3 query.addCriteria(Criteria.where("classNo").ne(2));
4 List<Student> students = mongoTemplate.find(query, Student.class);
5 log.warn("the query result is: {}", students);
6 }
输出如下:
14:39:19.805 WARN 83348 --- [ main] c.e.demo.learn.mongo.MongodbController : the query result is:
[Student(_id=674d8125bf8e9e35bbc08718, name=xiaoa, description=good1, classNo=1, age=15),
Student(_id=674d8125bf8e9e35bbc08719, name=xiaob, description=good2, classNo=1, age=13),
Student(_id=674d8125bf8e9e35bbc0871a, name=xiaoc, description=good3, classNo=1, age=15),
Student(_id=674d8125bf8e9e35bbc0871b, name=xiaod, description=good4, classNo=1, age=15),
Student(_id=674d8153c993425aaa5c4fec, name=zhongd, description=perfect2, classNo=3, age=15),
Student(_id=674d81dc8130705614f23311, name=biga, description=nice, classNo=3, age=15),
Student(_id=674d81dd8130705614f23312, name=bigb, description=nice, classNo=3, age=13),
Student(_id=674d81dd8130705614f23313, name=bigc, description=nice, classNo=3, age=15),
Student(_id=674d81dd8130705614f23314, name=bigd, description=nice, classNo=3, age=15)]
观察代码,我们发现需要首先创建一个Query 实例,表示是一个查询动作。
query 对象,继续补充一个Criteria 实例。Criteria 英[kraɪ'tɪəriə] 译为比标准、准则、尺度。我们可以直接理解为查询条件。
注意Criteria 实例是由 Criteria.where 方法创建出来的。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )这是一个简单工厂,参数为要查询的表的列名(文档的字段)。再跟一个in() ,表示列的in 操作,in() 中跟的是in操作的值。
最后直接用mongoTemplate 实例执行find 操作就好,条件为查询逻辑和表对应的类文件。
我们这里使用的是in 操作,除此之外,常用的还有
| 方法 | 作用 | 类比sql |
| gt | 表示 大于 | > |
| gte | 表示 大于等于 | >= |
| lt | 表示 小于 | < |
| lte | 表示 小于等于 | <= |
| ne | 表示 不等于 | != |
| nin | 表示 不属于 | not in |
| is | 表示等于 | = |
|
regex |
表示 like (注意后面跟正则表达式,如 "^.*" + queryKeyWord + ".*$") | like ‘%关键字%’ |
这些都是基本操作,有sql经验的同学肯定明白具体怎么使用。
我们再补充一个模糊查询的例子:
1 private void simpleRegexQuery() {
2 Query query = new Query();
3 String queryKeyWord = "ong";
4 query.addCriteria(Criteria.where("name").regex("^.*" + queryKeyWord + ".*$"));
5 List<Student> students = mongoTemplate.find(query, Student.class);
6 log.warn("the query result is: {}", students);
7 }
输出如下:
2024-12-03 14:46:23.781 WARN 81708 --- [ main] c.e.demo.learn.mongo.MongodbController : the query result is:
[Student(_id=674d8152c993425aaa5c4fe9, name=zhonga, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fea, name=zhongb, description=perfect2, classNo=2, age=13),
Student(_id=674d8153c993425aaa5c4feb, name=zhongc, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fec, name=zhongd, description=perfect2, classNo=3, age=15)]
(2)接着来看一个相对复杂点的组合条件:
两个或条件,类似于SQL中的: A表达式 OR B表达式,代码如下
1 private void simpleOrQuery() {
2 Query query = new Query();
3 String queryKeyWord = "ong";
4 Criteria neCri = Criteria.where("age").ne(15);
5 Criteria regexCri = Criteria.where("name").regex("^.*" + queryKeyWord + ".*$");
6 Criteria orCri = new Criteria().orOperator(neCri, regexCri);
7 query.addCriteria(orCri);
8 List<Student> students = mongoTemplate.find(query, Student.class);
9 log.warn("the query result is: {}", students);
10 }
执行效果如下:
2024-12-03 14:48:28.787 WARN 83804 --- [ main] c.e.demo.learn.mongo.MongodbController : the query result is:
[Student(_id=674d8125bf8e9e35bbc08719, name=xiaob, description=good2, classNo=1, age=13),
Student(_id=674d8152c993425aaa5c4fe9, name=zhonga, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fea, name=zhongb, description=perfect2, classNo=2, age=13),
Student(_id=674d8153c993425aaa5c4feb, name=zhongc, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fec, name=zhongd, description=perfect2, classNo=3, age=15),
Student(_id=674d81dd8130705614f23312, name=bigb, description=nice, classNo=3, age=13)]
我们创建好两个Criteria的简单条件之后,再创建一个新的Criteria 实例,用一个or操作将二者关联起来.
query 接收最新的Criteria 实例,然后执行查询即可。
这里的写法类似于sql中的
where name like "%ong%" or age != 15
如果是两个AND 条件,类似于SQL中的: (防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )A表达式 AND B表达式,用法和or的使用方法是一样的 。这里就不举例了,
我们这里写一个复杂的用法:
1 private void complexQuery() {
2 Query query = new Query();
3
4 String queryKeyWord = "ong";
5 Criteria ageCri = Criteria.where("age").ne(15);
6 Criteria nameCri = Criteria.where("name").regex("^.*" + queryKeyWord + ".*$");
7 Criteria cri1 = new Criteria().orOperator(ageCri, nameCri);
8
9 Criteria descCri = Criteria.where("description").is("nice");
10 Criteria classNoCri = Criteria.where("classNo").in(1, 2, 3);
11 Criteria cri2 = new Criteria().andOperator(descCri, classNoCri);
12
13 query.addCriteria(new Criteria().orOperator(cri1, cri2));
14 List<Student> students = mongoTemplate.find(query, Student.class);
15 log.warn("the query result is: {}", students);
16 }
输出如下:
2024-12-03 14:51:46.908 WARN 92840 --- [ main] c.e.demo.learn.mongo.MongodbController : the query result is:
[Student(_id=674d8125bf8e9e35bbc08719, name=xiaob, description=good2, classNo=1, age=13),
Student(_id=674d8152c993425aaa5c4fe9, name=zhonga, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fea, name=zhongb, description=perfect2, classNo=2, age=13),
Student(_id=674d8153c993425aaa5c4feb, name=zhongc, description=perfect2, classNo=2, age=15),
Student(_id=674d8153c993425aaa5c4fec, name=zhongd, description=perfect2, classNo=3, age=15),
Student(_id=674d81dc8130705614f23311, name=biga, description=nice, classNo=3, age=15),
Student(_id=674d81dd8130705614f23312, name=bigb, description=nice, classNo=3, age=13),
Student(_id=674d81dd8130705614f23313, name=bigc, description=nice, classNo=3, age=15),
Student(_id=674d81dd8130705614f23314, name=bigd, description=nice, classNo=3, age=15)](防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
这里的写法类似于sql中的
where ( description = "nice" and classNo in (1 ,2 ,3) ) or ("name like %ong%" or age != 15)
总体来看
一个Criteria 实例,就是一个查询条件。我们可以通过 or、and 操作来不断的组合生成一个新的Criteria实例,也就是一个新的查询条件 ,并且可以以此查询条件继续组合生成更高级的Criteria。以此不断的类推。这个过程就像垒积木一样:

(3) 接着我们整合下分页功能,并且以班级排序
PageRequest pageable = PageRequest.of(pageIndex - 1, pageSize);
Query pageQuery=query.with(pageable).with(Sort.by(Sort.Direction.DESC,"classNo"));
注意分页时,页码数是从0开始,所以要-1。同时排序使用Sort生成sort的对象,包含排序方式和字段,并且这里支持多级排序。
整体代码如下:
1 private void complexPageQuery() {
2 int pageIndex=2;
3 int pageSize=3;
4 Query query = new Query();
5 String queryKeyWord = "ong";
6 Criteria ageCri = Criteria.where("age").ne(15);
7 Criteria nameCri = Criteria.where("name").regex("^.*" + queryKeyWord + ".*$");
8 Criteria cri1 = new Criteria().orOperator(ageCri, nameCri);
9
10 Criteria descCri = Criteria.where("description").is("nice");
11 Criteria classNoCri = Criteria.where("classNo").in(1, 2, 3);
12 Criteria cri2 = new Criteria().andOperator(descCri, classNoCri);
13
14 query.addCriteria(new Criteria().orOperator(cri1, cri2));
15 long allDataSize = mongoTemplate.count(query, Student.class);
16 PageRequest pageable = PageRequest.of(pageIndex - 1, pageSize);
17 Query pageQuery=query.with(pageable).with(Sort.by(Sort.Direction.DESC,"classNo"));
18 List<Student> students = mongoTemplate.find(pageQuery, Student.class);
19 log.warn("the query result is: {}", students);
20 }
输出如下:
2024-12-03 14:56:46.059 WARN 18516 --- [ main] c.e.demo.learn.mongo.MongodbController : the query result is:
[Student(_id=674d81dd8130705614f23314, name=bigd, description=nice, classNo=3, age=15),
Student(_id=674d81dc8130705614f23311, name=biga, description=nice, classNo=3, age=15),
Student(_id=674d8152c993425aaa5c4fe9, name=zhonga, description=perfect2, classNo=2, age=15)]
基于 MongoTemplate 实现MongoDB的复杂查询的更多相关文章
- mongodb的高级查询
db的帮助文档 输入:db.help(); db.AddUser(username,password[, readOnly=false]) 添加用户 db.auth(usrename,passwor ...
- 基于C#的MongoDB数据库开发应用(2)--MongoDB数据库的C#开发
在上篇博客<基于C#的MongoDB数据库开发应用(1)--MongoDB数据库的基础知识和使用>里面,我总结了MongoDB数据库的一些基础信息,并在最后面部分简单介绍了数据库C#驱动的 ...
- 【转】MongoDB学习笔记(查询)
原文地址 MongoDB学习笔记(查询) 基本查询: 构造查询数据. > db.test.findOne() { "_id" : ObjectId("4fd58ec ...
- 【第十二章】 springboot + mongodb(复杂查询)
简单查询:使用自定义的XxxRepository接口即可.(见 第十一章 springboot + mongodb(简单查询)) 复杂查询:使用MongoTemplate以及一些查询条件构建类(Bas ...
- 第十二章 springboot + mongodb(复杂查询)
简单查询:使用自定义的XxxRepository接口即可.(见 第十一章 springboot + mongodb(简单查询)) 复杂查询:使用MongoTemplate以及一些查询条件构建类(Bas ...
- mongodb 高级聚合查询
mongodb高级聚合查询 在工作中会经常遇到一些mongodb的聚合操作,特此总结下.mongo存储的可以是复杂类型,比如数组.对象等mysql不善于处理的文档型结构,并且聚合的操作也比mysq ...
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 写入和查询)--学习笔记
2.5.3 MongoDB -- 写入和查询 写入 查询 查找操作符 逻辑操作符 其他 嵌套对象 数组 游标方法 写入 https://docs.mongodb.com/manual/tutorial ...
- 基于Solr的HBase多条件查询测试
背景: 某电信项目中采用HBase来存储用户终端明细数据,供前台页面即时查询.HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级 的快 速检索,对于多字段的组合查询却无能为力.针对HBa ...
- MongoDB 覆盖索引查询
MongoDB 覆盖索引查询 官方的MongoDB的文档中说明,覆盖查询是以下的查询: 所有的查询字段是索引的一部分 所有的查询返回字段在同一个索引中 由于所有出现在查询中的字段是索引的一部分, Mo ...
- MongoDB 入门之查询(find)
MongoDB 入门之查询(find) 1. find 简介 (1)find的第一个参数决定了要返回哪些文档. 空的查询文档会匹配集合的全部内容.默认就是{}.结果将批量返回集合c中的所有文档. db ...
随机推荐
- Asp.net 获取客户端的信息
Response.Write("客户端计算机名:" + Request.UserHostName + "<BR />"); Response.Wri ...
- CSIG青年科学家会议圆满举行,合合信息打造智能文档处理融合研究新范式
近期,第十九届中国图象图形学学会青年科学家会议(简称"会议")在广州召开.会议由中国图象图形学学会(CSIG)主办,琶洲实验室.华南理工大学.中山大学.中国图象图形学学 ...
- C++ STL(标准模版库)—— vector 与 迭代器
STL 基本概念 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称. STL 从广义上讲分为三类:algorithm(算法).containe ...
- 如何使用Java在Word中插入表格
序言 各位好啊,我是会编程的蜗牛,作为java开发者,有时候需要操作word或者excel.这里面比较常用的框架是POI,我之前用过POI来读写excel,也有用过alibaba easy excel ...
- LeetCode 407. 接雨水 II (优先队列)
参考 优先队列的思路解决接雨水II,逐行解释 从最外圈开始不断向内遍历,如果内部的高度小于外部的高度,则证明该位置可以蓄水,否则不能,水会顺着该外圈流出去. 每次都处理外圈高度最小的那个位置 a,遍历 ...
- Android Qcom USB Driver学习(三)
usb hub区分端口 USB 子系统拓扑浅析 USB ID Database VendorID and ProductID usb usb1: New USB device found, idVen ...
- 分类问题的评价指标AUC
- 墨天轮专访星环科技刘熙:“向量热”背后的冷思考,Hippo如何打造“先发”优势?
导读: 深耕技术研发数十载,坚持自主可控发展路.星环科技一路砥砺前行.坚持创新为先,建设了全面的产品矩阵,并于2022年作为首个独立基础软件产品公司成功上市.星环科技在今年的向星力•未来技术大会上发布 ...
- 在实例化对象的时候new关键字具体做了哪些操作?
a 创建了一个空对象 {}b 通过原型链把空对象和构造函数连接起来__proto__ = prototype c 构造函数的this指向新对象,并执行函数体 d 判断构造函数的返回值,返回对象就使用该 ...
- vue 的响应式原理
首先,遍历data的数据,通过 Obejct.defineProperty 定义数据,给数据加上 geter 和 setter 函数,获取数据触发 getter函数, 修改数据时触发 setter函数 ...