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)]