基于 MongoTemplate 實現MongoDB的復雜查詢
MongoDB是典型的非關系型數據庫,但是它的功能越來越復雜,很多項目中,我們為了快速拓展,甚至直接使用Mongo 來替代傳統DB做數據持久化。
雖然MongoDB在支持具體業務時沒有問題,但是由于它是文檔型數據庫,擁有一套獨立的語法,不再支持傳統的SQL。
開發人員發現在實際開發過程中,由于語法問題,在處理復雜的業務查詢時,不知該如何下手,使不上勁。
在這里我總結了一下接觸到的使用場景:
如果是簡單的業務,那么我們直接使用spring JPA來實現就可以,比如這些操作:
1、創建
2、刪除
3、修改
4、簡單的查詢
因為這些語句的邏輯往往不是很復雜,JPA完全可以勝任,而且還清晰直觀。
如果是復雜的場景,我們就使用MongoTemplate 來組織條件邏輯:
假設背景是有張Student 表,結構如下:
1 @Data 2 @Document("temp_Student") 3 public class Student { 4 5 private String _id; 6 7 private String name; 8 9 private String description; 10 11 private int classNo; 12 13 private int age; 14 }
我們已經預先插入了下邊的數據:

(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.rzrgm.cn/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.rzrgm.cn/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.rzrgm.cn/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)]
如果你覺得寫的不錯,歡迎轉載和點贊。 轉載時請保留作者署名jilodream/王若伊_恩賜解脫(博客鏈接:http://www.rzrgm.cn/jilodream/

浙公網安備 33010602011771號