MongoDB數據庫查詢,和SpringBoot整合使用 ,@query的用法

前序說明:(隨時補充更新

關於Mongo數據庫的網上資料又亂又少,所以針對用過的進行一個循序漸進的總結;

  1. 關於Mongo(如果覺得關於不想看,直接跳到使用階段 2)
  2. Mongo的使用:
    (1) 數據庫中常用的查詢 shell 寫法實現總結;
    (2)SpringBoot和Mongo整合的一些使用優勢:
    (3)mongoDB中 service層實現query方式拼接sql;
    (4)在DAO層,使用@query註解實現 sql的方式;
    EG:特殊的一些操作:查詢一個Collection ,指定返回的字段;

一、關於MongoDB

1. MongoDB是什麼?

MongoDB(是一款C++編寫的非常熱門的Nosql,面向完蛋的數據庫管理系統)是一個基於分佈式文件存儲的數據庫,是一個介於關係數據庫和非關係數據庫當中功能最豐富,最像關係數據庫的。他支持的數據結構非常鬆散,是類似json的bson格式,因此可以存儲比較複雜的數據類型。Mongo最大的特點是他支持的查詢語言非常強大,其語法有點類似於面向對象的查詢語言,幾乎可以實現類似關係數據庫單表查詢的絕大部分功能,而且還支持對數據建立索引。

2. 爲什麼要使用MongoDB? 有哪些優勢和不足?不適用的場景?

優勢:
(1)查詢非常快:由於MongoDB獨特的數據處理方式,可以將熱點數據加載到內存,故而對查詢來講,會非常快(當然也會非常消耗內存),MongoDB數據存在內存,由linux系統mmap實現,當內存不夠時,只將熱點數據放入內存,其他數據存在磁盤;所以在這裏,重要的是要有正確的索引和足夠強大的RAM來從MongoDB中獲益;
(2)Bson的數據結構,很好操作和處理:(可以存儲多個類型的值到數據庫中)同時由於採用了BSON的方式存儲數據,故而對JSON格式數據具有非常好的支持性以及友好的表結構修改性,文檔式的存儲方式,數據友好可見;
(3)數據庫的分片集羣負載具有非常好的擴展性以及非常不錯的自動故障轉移(大讚)。(內置Auto-Sharding自動分片支持雲級擴展性,分片簡單)
(4)內置GridFS,支持大容量存儲;GridFS是一個出色的分佈式文件系統,可以支持海量的數據存儲。內置了GridFS 的MongoDB,能夠滿足大數據集的快速範圍查詢。如果在平時的開發過程中,有數據集非常大的情況,可以使用它來進行處理;
(5)全索引支持: 它的索引能夠擴展到內部對象和內嵌的數組,也就是說,如果一個對象有一個內嵌對象,MongoDB可以針對內嵌對象中的字段進行索引的添加;
(6)MongoDB支持複雜的聚合,(下面會有一個栗子,當時寫一個超級複雜的聚合方法,寫了倆小時…)(個人覺得,如果瞭解透了那些詞的作用,寫出一個聚合會很不錯的。)

不足:
(1)數據庫的查詢採用了特有的查詢方式,有一定的學習成本(不高);
(2)鎖只能提供到collection級別,還做不到行級鎖;
(3)沒有事務機制(不能回滾啊); (這裏被好心的網友提醒了,剛纔去查新鮮資料的時候,還是有很多的文章總結說依舊不支持事務。其實單獨針對事務去搜索看看的時候,就知道 —MongoDB 4.0 引入的事務功能。 敲重點:看官方文檔很重要。 關於MongoDB事務的點 這裏就先不展開講了。待研究一下 )(剛看了三個比較正規的教程網址,第一句上來就說 不支持事務,我的膝蓋。。)
所以這裏還是附上官網地址: MongoDB官網
MongoDB的事務
【For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions. With distributed transactions, transactions can be used across multiple operations, collections, databases, documents, and shards.】同時在使用事務的時候,可以自定義讀首選項,以及讀寫權限的範圍;
(4)學習資料肯定沒有MySQL的多。

不適用的場景:
需要使用複雜sql的查詢;(這裏的複雜不是指需要高度聚合的那種,而是表與表之間進行的複雜查詢);

3. Nosql數據庫的理論基礎 和MongoDB相關

(1) CAP理論: 分別代表 Consistency(強一致性),Availability(可用性),Partition Tolerance(分區容錯);
C:系統在執行某項操作後仍然處於一致的狀態。在分佈式系統中,更新操作執行成功之後,所有的用戶都能讀取到最新的值,這樣的系統被認爲具有強一致性。
A:用戶執行的操作在一定時間內,必須返回結果。如果超時,那麼操作回滾,跟操作沒有發生一樣。
P:分佈式系統是由多個分區節點組成的,每個分區節點都是一個獨立的Server,P屬性表明系統能夠處理分區節點的動態加入和離開。

(2) 在構建分佈式系統的時候,必須考慮CAP特性。
①傳統的關係型DB,注重的是CA特性(分區容錯性),數據一般存儲在一個server上。
②而處理海量數據的分佈式存儲和處理系統高更注重AP(強一致性),Nosql保留數據的最終一致性。

4. MongoDB支持的數據類型:

(1) 字符串 - 這是用於存儲數據的最常用的數據類型。MongoDB中的字符串必須爲UTF-8。
(2) 整型 - 此類型用於存儲數值。 整數可以是32位或64位,具體取決於服務器。
(3) 布爾類型 - 此類型用於存儲布爾值(true / false)值。
(4) 雙精度浮點數 - 此類型用於存儲浮點值。
(5) 最小/最大鍵 - 此類型用於將值與最小和最大BSON元素進行比較。
(6) 數組 - 此類型用於將數組或列表或多個值存儲到一個鍵中。
(7) 時間戳 - ctimestamp,當文檔被修改或添加時,可以方便地進行錄製。
(8) 對象 - 此數據類型用於嵌入式文檔。
(9) Null - 此類型用於存儲Null值。
(10) 符號 - 該數據類型與字符串相同; 但是,通常保留用於使用特定符號類型的語言。
(11) 日期 - 此數據類型用於以UNIX時間格式存儲當前日期或時間。您可以通過創建日期對象並將日,月,年的日期進行指定自己需要的日期時間。
(12) 對象ID - 此數據類型用於存儲文檔的ID。
(13) 二進制數據 - 此數據類型用於存儲二進制數據。
(14) 代碼 - 此數據類型用於將JavaScript代碼存儲到文檔中。
(15) 正則表達式 - 此數據類型用於存儲正則表達式。

5. 學習鏈接:

簡書教程(包括常用的一些命令)
簡書 可視化工具和一些命令
可視化工具使用教程

二、 數據庫中常用的查詢 shell 寫法實現總結

1. 在navicat中操作實現查詢sql;

這個就比較簡單了,有一個非常簡單的方法:
就是在navicat軟件中選擇具體的某個collection 構建查詢語句,點擊確定,即可自動生成查詢語句;
@query中的條件,也可以使用這種方式,生成query語句,放在@query的value中;

2. 常用的一些查詢:

關鍵詞:
$gt大於
$lt小於
$ne不等於
$gte大於或等於
$lte小於或等於
$inc可以對文檔的某個值爲數字型(只能爲滿足要求的數字)的鍵進行增減的操作。
$in相當於T-SQL中的in
$nin相當於T-SQL中的not in
$set用來指定一個鍵並更新鍵值,若鍵不存在並創建。
KaTeX parse error: Expected '}', got 'EOF' at end of input: … "20120002"},{"inc":{“size” : 1}})
$set用來指定一個鍵並更新鍵值,若鍵不存在並創建。

  • db.a.update({“uid” : “20120002”},{"$set":{“size”:10}})

$unset主要是用來刪除鍵。

  • db.a.update({“uid” : “20120002”},{"$unset":{“sname”:“abc”}})

$push向數組添加新的值。如果鍵值不存在,則創建一個。

  • db.c.update({“name” : “toyota”},{$push:{“title”:“t1”}})

$addToSet主要給數組類型鍵值添加一個元素時,避免在數組中產生重複數據。

  • db.c.update({“name” : “toyota”},{$addToSet:{“title”:“t2”}})

$pop從數組的頭或者尾刪除數組中的元素

  • db.c.update({“name” : “toyota”},{$pop:{“title”:1}})

$pull從數組中刪除滿足條件的元素

  • db.c.update({“name” : “toyota”},{$pull:{“title”:“t2”}})

三、 SpringBoot和Mongo整合的一些使用優勢:

1. DAO繼承MongoRepository<Object, String>;

這個MongoRepository是mongo提供的一個封裝好的基類,相當於SpringDataJpa的思想,(重點:儘管裏面沒有定義任何一個方法,想要使用封裝好的,就需要繼承;)
(1)可以通過 方法名稱直接生成對應的sql;
和JPA的思想差不多:
比如:根據用戶名稱查找 對應的用戶信息:findByUserName(String userName);

一些常用的:
· {countBy的使用} – 根據userName查詢所有符合條件的count: countByUserName();
· {In的使用 } – 根據用戶年級查詢符合在list參數中的條目:findByGradeIn(List gradeList);
· {Contains和Between的使用} – 查詢方法列表包含參數1以及完成時間在參數2.3之間的所有條目:findByMethodListContainsAndFinishTimeBetween()

(2)使用@Query進行查詢條件的拼接:

  • 小竅門
	@Query("{ userName: ?0, is_delete : false }")
    List<User> findByUserName(StringuserName);

這裏有個小竅門:Query中的條件查詢語句的構建
可以使用navicat進行構建, 構建完成之後,直接放進來就成;
在這裏插入圖片描述

  • @Query 介紹一下Query吧:
    value={} 表示條件;
    filed={} 表示返回哪幾個字段;

舉個例子
查詢一個Collection ,指定返回的字段;
【使用Query中的filed屬性來定義,1表示顯示,0表示不顯示;】

//只輸出id和title字段,第一個參數爲查詢條件,空代表查詢所有
db.news.find( {}, { id: 1, title: 1 } )
//如果需要輸出的字段比較多,不想要某個字段,可以用排除字段的方法
//不輸出內容字段,其它字段都輸出。
db.news.find( {}, {content: 0 } )

第一種實現 Criteria和query一起:
在這裏插入圖片描述
第二種實現:使用@quer{value="{}",field="{}"}的形式:

	@Query(value = "{is_disposed : false, status : { $nin : [0,2] }}", fields = "{request_id: 1,_id: 0}")
    List<LogHwPush> findByStatusAndIsDisposed();

經驗之談,這裏有個坑:
在value和field參數值中引號裏面都要有一個大括號
否則會報一個異常:org.bson.BsonInvalidOperationException: readStartDocument can only be called when CurrentBSONType is DOCUMENT, not when CurrentBSONType is STRING.
這個異常的大概意思是說:就是你查詢出來對應的結果 對應的也應該是一個大括號包含的 bson 格式的 document 而沒有大括號的話 就是對應的結果是String。 String是不能自己轉成bson格式的;
但是我當時硬是沒明白,使用了另一種方法解決:就是重新定義一個類,只接受filed中指定的參數,這樣是可以的,就是使用了java基礎,顯得有點笨;
就說 mongodb不可能這麼不完美!!!

  • 如果又想使用@query條件拼接,又想分頁;
    則可是這樣實現:
    Page getUserByUserName(PageAble pageable);
    ---- PageAble pageable = PageRequest.of(PageNumber number,PageSize size,Sort sort);

(3)也可以直接在service層,使用Repository直接調用 其中提供的好很多現成封裝好的 CRUD 以及 分頁 排序的方法;非常方便;

四、 mongoDB中 service層實現query方式拼接sql

1. 可以使用Criteria和query一起,進行sql的拼裝:

for Eg:分頁 條件查詢,並且根據某個字段進行排序:

	//使用MongoTemplate 
	@Autowired
    private MongoTemplate mongoTemplate;
 	@Override
    public List<User> getLogByMessageIdAndMethod() {
        List<Criteria> criteriaList = new ArrayList<>();
        criteriaList.add(Criteria.where("name").is("zhangsan"));
        criteriaList.add(Criteria.where("age").is("2"));
        Query query = new Query(new Criteria().andOperator(criteriaList.toArray(new Criteria[]{})));
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageAble page = PageRequest.of(0,100,sort);
        return mongoTemplate.find(query.with(page), User.class);
    }
2. 在service中通過Criteria 構建 update user set userName =“zhangsan” where user_id = “1234567890”;
Criteria criteria = new Criteria() {
            @Override
            public Document getCriteriaObject() {
                Document criteriaObject = new Document();
                criteriaObject.put("status", User.Status.READY);
                criteriaObject.put("$where", "this.a= this.b");
                return criteriaObject;
            }
        };
        Update update = new Update().set("status", User.Status.FINISHED)
                .set("update_time", new Date());
        UpdateResult result = mongoOperations.updateMulti(new Query(criteria), update, User.class);

六、 現實使用中 特殊 的一些操作:

1. mongo的聚合查詢 SpringData mongo:

todo:根據name進行聚合 分組查詢年齡總和、第一個年齡、和將年齡放入一個set集合中返回
插入數據:

		mongoTemplate.save(new Role("zhang1",5));
        mongoTemplate.save(new Role("zhang2",6));
        mongoTemplate.save(new Role("zhang3",12));
        mongoTemplate.save(new Role("zhang4",14));
        mongoTemplate.save(new Role("zhang5",23));
        mongoTemplate.save(new Role("zhang1",6));
        mongoTemplate.save(new Role("zhang5",24));

查詢:

		 TypedAggregation<Role> agg = Aggregation.newAggregation(Role.class,
                Aggregation.group("name").
                        sum("age").as("agesum").
                        first("age").as("agefirst").
                        addToSet("age").as("agess")
                );
        AggregationResults<Document> result = mongoTemplate.aggregate(agg,Document.class);
        result.getMappedResults().forEach(document -> System.out.println(document));
        

結果:

Document{{_id=zhang1, agesum=11, agefirst=5, agess=[6, 5]}}
Document{{_id=zhang2, agesum=6, agefirst=6, agess=[6]}}
Document{{_id=zhang3, agesum=12, agefirst=12, agess=[12]}}
Document{{_id=zhang5, agesum=47, agefirst=23, agess=[24, 23]}}
Document{{_id=zhang4, agesum=14, agefirst=14, agess=[14]}}

太棒的一個網址總結SpringData結合mongo的使用:https://juejin.im/post/5afb9de8518825426c690307

總結:

  1. Aggregation:看其源碼可知,其中有很多的操作,
    比如:sort(),group(), sortByCount(),skip(),limit(),simple(),match(Criteria criteria)匹配某個Criteria條件,
  2. group的一些特性:
    count(),sum(),addToSet(),last(),first(),avg(),push(),min(),max().
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章