ac86u做網(wǎng)站服務(wù)器百度競價(jià)推廣方案范文
一、 MongoDB 簡介
1 什么是 MongoDB
MongoDB 是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫。由 C++語言編寫。在為 WEB 應(yīng)用提供可擴(kuò)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。
MongoDB 是一個(gè)介于關(guān)系數(shù)據(jù)庫和非關(guān)系數(shù)據(jù)庫之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫的。它支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類似 json 的 bson 格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類型。Mongo 最大的特點(diǎn)是它支持的查詢語言非常強(qiáng)大,其語法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。
2 什么是 NoSQL
NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是 SQL”,是一項(xiàng)全新的數(shù)據(jù)庫革命性運(yùn)動(dòng),早期就有人提出,發(fā)展至 2009 年趨勢越發(fā)高漲。NoSQL 的擁護(hù)者們提倡運(yùn)用非關(guān)系型 的數(shù)據(jù)存儲(chǔ),相對于鋪天蓋地的關(guān)系型數(shù)據(jù)庫運(yùn)用,這一概念無疑是一種全新的思維的注入。
3 NoSQL 數(shù)據(jù)庫的分類
3.1鍵值(Key-Value)存儲(chǔ)數(shù)據(jù)庫
這一類數(shù)據(jù)庫主要會(huì)使用到一個(gè)哈希表,這個(gè)表中有一個(gè)特定的鍵和一個(gè)指針指向特定 的數(shù)據(jù)。Key/value 模型對于 IT 系統(tǒng)來說的優(yōu)勢在于簡單、易部署。但是如果 DBA 只對部 分值進(jìn)行查詢或更新的時(shí)候,Key/value 就顯得效率低下了。例如: Redis
3.2列存儲(chǔ)數(shù)據(jù)庫
這部分?jǐn)?shù)據(jù)庫通常是用來應(yīng)對分布式存儲(chǔ)的海量數(shù)據(jù)。鍵仍然存在,但是它們的特點(diǎn)是 指向了多個(gè)列。這些列是由列家族來安排的。如:HBase。
3.3文檔型數(shù)據(jù)庫
文檔型數(shù)據(jù)庫的靈感是來自于 Lotus Notes 辦公軟件的,而且它同第一種鍵值存儲(chǔ)相類 似。該類型的數(shù)據(jù)模型是版本化的文檔,半結(jié)構(gòu)化的文檔以特定的格式存儲(chǔ),比如 JSON。 文檔型數(shù)據(jù)庫可 以看作是鍵值數(shù)據(jù)庫的升級版,允許之間嵌套鍵值。而且文檔型數(shù)據(jù)庫比 鍵值數(shù)據(jù)庫的查詢效率更高。如:CouchDB, MongoDB. 國內(nèi)也有文檔型數(shù)據(jù)庫 SequoiaDB, 已經(jīng)開源。
3.4圖形(Graph)數(shù)據(jù)庫
圖形結(jié)構(gòu)的數(shù)據(jù)庫同其他行列以及剛性結(jié)構(gòu)的 SQL 數(shù)據(jù)庫不同,它是使用靈活的圖形模型,并且能夠擴(kuò)展到多個(gè)服務(wù)器上。NoSQL 數(shù)據(jù)庫沒有標(biāo)準(zhǔn)的查詢語言(SQL),因此進(jìn)行 數(shù)據(jù)庫查詢需要制定數(shù)據(jù)模型。許多 NoSQL 數(shù)據(jù)庫都有 REST 式的數(shù)據(jù)接口或者查詢 API。 如:Neo4J, InfoGrid。
二、 MongoDB 與關(guān)系型數(shù)據(jù)庫對比
1 與關(guān)系型數(shù)據(jù)庫術(shù)語對比
2 存儲(chǔ)數(shù)據(jù)對比
3 RDBMS 與 MongoDB 對應(yīng)的術(shù)語
三、 MongoDB 的數(shù)據(jù)類型
四、 MongoDB 的下載與安裝
1 下載 MongoDB
下載地址:https://www.mongodb.com/download-center/community
2 安裝 MongoDB
2.1下載 ForLinux 平臺(tái)的 MongoDB
2.2Linux 安裝
在 Linux 平臺(tái)的 MongoDB 為解壓版。我們只要解壓 tgz 文件就可以使用。
將下載的 tgz 包上傳到 Linux 環(huán)境中
我將 tgz 包上傳到了自己創(chuàng)建的 temp 目錄中。該目錄位于/root 目錄中。
解壓 tgz 文件
通過 tar 命令對 tgz 文件做解壓處理。
移動(dòng) MongoDB
我們將解壓完的 MongoDB 目錄移動(dòng)到/usr/local 目錄中并改名為 mongodb。
創(chuàng)建數(shù)據(jù)庫目錄
MongoDB 的數(shù)據(jù)存儲(chǔ)在 data 目錄的 db 目錄下,但是這個(gè)目錄在安裝過程不會(huì)自動(dòng)創(chuàng)建,需要手動(dòng)創(chuàng)建 data 目錄,并在 data 目錄中創(chuàng)建 db 目錄。data 目錄可以創(chuàng)建在任何位置。 本文檔中,我們將 data 目錄創(chuàng)建在 mongodb 的根目錄下。
至此 Linux 平臺(tái)中的 MongoDB 就已經(jīng)安裝完畢。
3 MongoDB 的啟動(dòng)與關(guān)閉
3.1啟動(dòng) MongoDB
MongoDB 的啟動(dòng)方式分為兩種
1)前置啟動(dòng)
2)后置啟動(dòng)
無論哪種啟動(dòng)方式都需要執(zhí)行 bin 目錄中的 mongod 命令。MongoDB 在啟動(dòng)時(shí)默認(rèn)的查找數(shù)據(jù)庫的路徑為/data/db。如果我們數(shù)據(jù)庫路徑有變化,需要在該命令中通過–dbpath 參數(shù)來指定 db 目錄的路徑(該路徑可以是絕對路徑,也可是相對路徑)。
前置啟動(dòng)
MongoDB 的默認(rèn)啟動(dòng)方式為前置啟動(dòng)。所謂前置啟動(dòng)就是 MongoDB 啟動(dòng)進(jìn)程后會(huì)占用當(dāng)前終端窗口。
進(jìn)入到 MongoDB 的 bin 目錄。
執(zhí)行 bin 目錄中的 mongod 命令。
由于我們的 db 目錄放在 mongodb 的根下,所以在執(zhí)行該命令時(shí)需要通過 --dbpath 參數(shù) 指定 db 路徑。
啟動(dòng)后會(huì)在終端中輸出一些啟動(dòng)信息。此時(shí)終端窗口已被啟動(dòng)進(jìn)程所占用。我們通過啟 動(dòng)信息可以看到 MongoDB 默認(rèn)的監(jiān)聽端口為 27017
按 Ctrl+C 可結(jié)束啟動(dòng)進(jìn)程關(guān)閉 MongoDB
后置啟動(dòng)
所謂后置啟動(dòng)就是以守護(hù)進(jìn)程的方式啟動(dòng) MongoDB。我們需要在執(zhí)行 mongod 命令中 添加 --fork 參數(shù)。需要注意的是,–fork 參數(shù)需要配合著–logpath 或者是–syslog 參數(shù)使用。 --logpath 與–syslog 參數(shù)是指定 MongoDB 的日志文件。MongoDB 的日志文件可以在系統(tǒng)中的任意位置,我們在 mongodb 目錄下創(chuàng)建 log 目錄,在該目錄中創(chuàng)建一個(gè)名為 mongodb.log 的日志文件。
創(chuàng)建 log 目錄
在 log 目錄中創(chuàng)建 mongodb.log 日志文件
后置啟動(dòng) MongoDB
常見的啟動(dòng)參數(shù)
通過配置文件加載啟動(dòng)參數(shù)
如果覺得在啟動(dòng) MongoDB 時(shí)給定的參數(shù)項(xiàng)太多,那么我們也可以通過配置文件來配置 啟動(dòng)參數(shù),配置文件可以在任意目錄中,配置文件的擴(kuò)展名應(yīng)為.conf,配置文件中使用 key=value 結(jié)構(gòu)。在執(zhí)行 MongoDB 時(shí)通過–config 參數(shù)來指定需要加載的配置文件。
我們在 mongodb 目錄下創(chuàng)建一個(gè) etc 目錄,在該目錄中創(chuàng)建一個(gè)名為 mongodb.conf 的 配置文件。
創(chuàng)建 mongodb.conf 配置文件
編輯配置文件,在配置文件中添加配置項(xiàng):
1)指定 db 路徑
2)指定日志文件
3)配置端口
4)配置后端啟動(dòng)
在配置文件中配置啟動(dòng)參數(shù)時(shí)需要注意的是,在參數(shù)前不在加–符號,直接以參數(shù)名作 為 key 就可以。
通過加載配置文件啟動(dòng) MongoDB
配置環(huán)境變量
為了能夠在任何目錄中執(zhí)行 bin 目錄中的命令,我們可以將 bin 目錄添加到環(huán)境變量中。 修 改 /etc/profile 文 件 , 添 加 export PATH=/usr/local/mongodb/bin:$PATH 。 /usr/local/monogdb/bin 為 MongoDB 的 bin 目錄的絕對路徑。可根據(jù)自己的情況來指定
重新加載/etc/profile 文件
測試結(jié)果
3.2關(guān)閉 MongoDB
使用 Ctrl+C 關(guān)閉
如果我們的啟動(dòng)方式是前置啟動(dòng),那么直接使用快捷鍵 Ctrl+C 就可以關(guān)閉 MongoDB。 這種關(guān)閉方式會(huì)等待當(dāng)前進(jìn)行中的的操作完成,所以依然是安全的關(guān)閉方式。
使用 kill 命令關(guān)閉
我們可以通過 Linux 的 kill 命令結(jié)束 MongoDB 進(jìn)程,然后刪除 data/db 目錄中的 mongod.lock 文件,否則下次無法啟動(dòng)。但是此方法不建議使用,因?yàn)闀?huì)造成數(shù)據(jù)損壞現(xiàn)象。
使用 MongoDB 的函數(shù)關(guān)閉
在 MongoDB 中提供了兩個(gè)關(guān)閉數(shù)據(jù)庫的函數(shù):
db.shutdownServer()
db.runCommand(“shutdown”)
如上兩個(gè)方法都需要在 admin 庫中執(zhí)行,并且都是安全的關(guān)閉方式。
使用 mongod 命令關(guān)閉 MongoDB
mongod --shutdown --dbpath<數(shù)據(jù)庫路徑>
mongod 命令的 shutdown 選項(xiàng)能安全的關(guān)閉 MongoDB 服務(wù)
五、 MongoDB 的用戶與權(quán)限管理
Mongodb 作為時(shí)下最為熱門的數(shù)據(jù)庫,那么其安全驗(yàn)證也是必不可少的,否則一個(gè)沒有驗(yàn)證的數(shù)據(jù)庫暴露出去,任何人可隨意操作,這將是非常危險(xiǎn)的。我們可以通過創(chuàng)建用戶的方式來降低風(fēng)險(xiǎn)。
1 Mongodb 用戶權(quán)限列表
Read | 允許用戶讀取指定數(shù)據(jù)庫 |
---|---|
readWrite | 允許用戶讀寫指定數(shù)據(jù)庫 |
dbAdmin | 允許用戶在指定數(shù)據(jù)庫中執(zhí)行管理函數(shù),如索引創(chuàng)建、刪除,查看 統(tǒng)計(jì)或訪問 system.profile |
userAdmin | 允許用戶向 system.users 集合寫入,可以找指定數(shù)據(jù)庫里創(chuàng)建、刪除和管理用戶 |
clusterAdmin | 只在 admin 數(shù)據(jù)庫中可用,賦予用戶所有分片和復(fù)制集相關(guān)函數(shù)的管理權(quán)限 |
readAnyDatabase | 只在 admin 數(shù)據(jù)庫中可用,賦予用戶所有數(shù)據(jù)庫的讀權(quán)限 |
readWriteAnyDatabase | 只在 admin 數(shù)據(jù)庫中可用,賦予用戶所有數(shù)據(jù)庫的讀寫權(quán)限 |
userAdminAnyDatabase | 只在 admin 數(shù)據(jù)庫中可用,賦予用戶所有數(shù)據(jù)庫的 userAdmin 權(quán)限 |
dbAdminAnyDatabase | 只在 admin 數(shù)據(jù)庫中可用,賦予用戶所有數(shù)據(jù)庫的 dbAdmin 權(quán)限 |
root | 只在 admin 數(shù)據(jù)庫中可用。超級賬號,超級權(quán)限 |
2 MongoDB 用戶使用
2.1創(chuàng)建 DB 管理用戶
mongodb 有一個(gè)用戶管理機(jī)制,簡單描述為,有一個(gè)管理用戶組,這個(gè)組的用戶是專門為管理普通用戶而設(shè)的,暫且稱之為管理員。
管理員通常沒有數(shù)據(jù)庫的讀寫權(quán)限,只有操作用戶的權(quán)限, 因此我們只需要賦予管理員 userAdminAnyDatabase 角色即可。
另外管理員賬戶必須在 admin 數(shù)據(jù)庫下創(chuàng)建
。
切換到 Admin 庫
管理員需要在 admin 數(shù)據(jù)庫下創(chuàng)建,所以我們需要切換到 admin 數(shù)據(jù)庫。
(在哪個(gè)庫下創(chuàng)建用戶,就得先切換到哪個(gè)數(shù)據(jù)庫)
查看 admin 中的用戶
我們可以通過 db.system.users.find()函數(shù)來查看 admin 庫中的所有用戶信息。
目前在 admin 庫中沒有用戶,所以查無結(jié)果。
db.createUser 函數(shù)
在 MongoDB 中可以使用 db.createUser({用戶信息})函數(shù)創(chuàng)建用戶。
db.createUser({user: "<name>",pwd: "<cleartext password>",customData: { <any information> },roles: [{ role: "<role>", db: "<database>" } | "<role>",...]
});
1)user:新建用戶名。
2)pwd:新建用戶密碼。
3)customData:存放一些用戶相關(guān)的自定義數(shù)據(jù),該屬性也可忽略。
4)roles:數(shù)組類型,配置用戶的權(quán)限。
創(chuàng)建管理員用戶
我們現(xiàn)在需要在 admin 庫中創(chuàng)建一個(gè)名為 bjsxt 的管理員用戶,密碼為 bjsxtpwd。
db.createUser({user:“bjsxt”,pwd:“bjsxtpwd”,roles:[{role:“userAdminAnyDatabase”,db:“admin”}]})
創(chuàng)建成功后會(huì)看到如下提示:
重啟 MongoDB
在管理員賬戶創(chuàng)建完成后,我們需要重新啟動(dòng) MongoDB,并開啟驗(yàn)證。 重新啟動(dòng)函數(shù):db.shutdownServer()。
使用權(quán)限方式啟動(dòng) MongoDB
在默認(rèn)的情況下 MongoDB 是不開啟用戶認(rèn)證的。如果我們添加用戶,那么需要開啟用 戶認(rèn)證機(jī)制。通過修改 mongodb.conf 配置文件,在文件中添加 auth=true 即可。
修改完成后啟動(dòng) MongoDB。
用戶認(rèn)證
創(chuàng)建管理員后,需要認(rèn)證方可使用該用戶,否則會(huì)提示需要認(rèn)證。
認(rèn)證函數(shù):db.auth(‘用戶名’,’密碼’)
如果結(jié)果返回 1,則表示認(rèn)證成功,返回 0 則表示認(rèn)證失敗。 登錄成功后可查詢用戶
2.2創(chuàng)建普通用戶
普通用戶由管理員創(chuàng)建。通常需要指定操作某個(gè)數(shù)據(jù)庫。
需求
我們創(chuàng)建一個(gè) sxt 數(shù)據(jù)庫,給這個(gè)數(shù)據(jù)庫添加一個(gè)用戶,用戶名為 itsxt,密碼為 itsxtpwd。 并授予該用戶對 sxt 數(shù)據(jù)庫進(jìn)行讀寫操作的權(quán)限。
使用管理員用戶登錄
普通用戶需要由管理員創(chuàng)建并授權(quán)。所以,我們首先做的就是用管理員賬戶登錄數(shù)據(jù)庫。
創(chuàng)建 sxt 數(shù)據(jù)庫
use 命令切換數(shù)據(jù)庫時(shí)如果該庫不存在,那么則會(huì)創(chuàng)建該數(shù)據(jù)庫。
(在哪個(gè)庫下創(chuàng)建用戶,就得先切換到哪個(gè)數(shù)據(jù)庫)
創(chuàng)建普通用戶
使用普通用戶
打開一個(gè)新的客戶端。
切換到 sxt 數(shù)據(jù)庫
由于我們是在 sxt 數(shù)據(jù)庫中創(chuàng)建的 itsxt 用戶,所以需要先切換到 sxt 庫。
登錄普通用戶
如果我們不登錄會(huì)發(fā)現(xiàn)無法對該數(shù)據(jù)庫進(jìn)行插入操作。因?yàn)槿鄙儆脩粽J(rèn)證。
通過認(rèn)證函數(shù)對用戶進(jìn)行登錄認(rèn)證。
認(rèn)證成功后操作通過該用戶操作 sxt 庫。該用戶對 sxt 庫具備讀寫操作。
2.3更新用戶角色
如果我們需要對已存在的用戶的角色做修改,那么我們可以使用 db.updateUser()函數(shù)來 更新用戶角色。注意,該函數(shù)需要當(dāng)前用戶具有 userAdminAnyDatabase 或者更高的權(quán)限。
更新角色語法格式
db.updateUser(“用戶名”, {“roles”:[{“role”:“角色名稱”},{“更新項(xiàng) 2”:“更新內(nèi)容”}]})
需求
目前 bjsxt 管理員用戶只具備 userAdminAnyDatabase 用戶管理角色,我們?yōu)樵撚脩籼砑?一個(gè) dbAdminAnyDatabase 數(shù)據(jù)庫管理角色。
更新角色
db.updateUser(“bjsxt”,{roles : [{“role”:“userAdminAnyDatabase”,“db”:“admin”},{“role”:“dbAdminAnyDatabase”,“db”:“admin”}]})
如果沒有提示任何信息則表示更新成功。退出當(dāng)前客戶端重新連接即可生效。
查看用戶信息
通過 show users 命令查看到 bjsxt 用戶的角色已經(jīng)發(fā)生改變。
2.4更新用戶密碼
更新用戶密碼有兩種方式:
1)使用 db.updateUser()函數(shù)更新密碼。
2)使用 db.changeUserPassword()函數(shù)更新密碼
更新密碼方式一
使用 db.upateUser()函數(shù)將 bjsxt 用戶的密碼修改為 sxt
語法格式
db.updateUser(“用戶名”,{“pwd”:“新密碼”})
如果未提示任何信息則表示更新成功。退出當(dāng)前客戶端重新連接認(rèn)證即可。
重新使用 bjsxt 用戶登錄
更新密碼方式二
使用 db.changeUserPassword()函數(shù)將 bjsxt 用戶的密碼修改為 sxtpwd。
語法格式
db.changeUserPassword(“用戶名”,“新密碼”)
如果未提示任何信息則表示更新成功。退出當(dāng)前客戶端重新連接認(rèn)證即可。
重新使用 bjsxt 用戶登錄
2.5刪除用戶
通過 db.dropUser()函數(shù)可刪除指定用戶。刪除成功后會(huì)返回 true。在刪除用戶時(shí)需要切換到創(chuàng)建用戶時(shí)所指定的數(shù)據(jù)庫中才可以刪除。注意:需要使用具有 userAdminAnyDatabse 角色管理員用戶才可以刪除其他用戶。
需求
我們使用 db.dropUser()函數(shù)將 itsxt 用戶刪除。
切換數(shù)據(jù)庫
itsxt 用戶在 sxt 數(shù)據(jù)庫中,所以需要先切換到 sxt 數(shù)據(jù)庫。
通過函數(shù)刪除用戶
我們可以看到,該函數(shù)返回了 true,表示刪除成功。
六、 MongoDB 的數(shù)據(jù)庫操作
1 創(chuàng)建數(shù)據(jù)庫
在 MongoDB 中創(chuàng)建數(shù)據(jù)庫的命令使用的是 use 命令。該命令有兩層含義:
1)切換到指定數(shù)據(jù)庫。
2)如果切換的數(shù)據(jù)庫不存在,則創(chuàng)建該數(shù)據(jù)庫。
我們使用 use 命令創(chuàng)建一個(gè)名為 sxttest 的數(shù)據(jù)庫。
2 查看所有數(shù)據(jù)庫
我們可以通過 show dbs 命令查看當(dāng)前 MongoDB 中的所有數(shù)據(jù)庫。
如果開啟了用戶認(rèn)證,則需要先登錄方可查看到結(jié)果,否則不顯示任何信息。如果使用 的是具備數(shù)據(jù)庫管理員角色的用戶,那么則可以看到 MongoDB 中的所有數(shù)據(jù)庫,如果使用 的普通用戶登錄的那么只能查詢到該用戶所擁有的數(shù)據(jù)庫。
用戶未登錄查詢數(shù)據(jù)庫。
使用具有數(shù)據(jù)庫管理員角色的用戶登錄查詢數(shù)據(jù)庫。
在查詢結(jié)果中并未包含我們剛剛創(chuàng)建的 sxttest 數(shù)據(jù)庫。因?yàn)?#xff0c;在 show dbs 命令中不顯 示未含有任何信息的數(shù)據(jù)的庫。
使用普通用戶登錄查詢數(shù)據(jù)庫。
我們在 sxt 數(shù)據(jù)庫中創(chuàng)建一個(gè)只具備讀寫權(quán)限的普通用戶。
使用普通用戶登錄并查詢數(shù)據(jù)庫。
3 刪除數(shù)據(jù)庫
在 MongoDB 中使用 db.dropDatabase()函數(shù)來刪除數(shù)據(jù)庫。在刪除數(shù)據(jù)庫之前,需要使用具備 dbAdminAnyDatabase 角色的管理員用戶登錄,然后切換到需要?jiǎng)h除的數(shù)據(jù)庫,執(zhí)行 db.dropDatabase()函數(shù)即可。刪除成功后會(huì)返回一個(gè){ “ok” : 1 }的 JSON 字符串。
我們現(xiàn)在將剛剛創(chuàng)建的 sxttest 刪除。
七、 MongoDB 的集合操作
MongoDB 中的集合是一組文檔的集,相當(dāng)于關(guān)系型數(shù)據(jù)庫中的表。
1 創(chuàng)建集合
MongoDB 使用 db.createCollection()函數(shù)來創(chuàng)建集合。
語法格式:db.createCollection(name, options)。
name: 要?jiǎng)?chuàng)建的集合名稱。
options: 可選參數(shù), 指定有關(guān)內(nèi)存大小及索引的選項(xiàng)。
options 可以是如下參數(shù)。
字段 | 類型 | 描述 |
---|---|---|
capped | 布爾 | (可選)如果為 true,則創(chuàng)建固定集合。固定集合是指有著固定大小的集合,當(dāng)達(dá)到最大值時(shí),它會(huì)自動(dòng)覆蓋最早的文檔。 當(dāng)該值為 true 時(shí),必須指定 size 參數(shù)。 |
autoindexid | 布爾 | (可選)如為 true,自動(dòng)在 _id 字段創(chuàng)建索引。默認(rèn)為 false。 |
size | 數(shù)值 | lse。 size 數(shù)值 (可選)為固定集合指定一個(gè)最大值(以字節(jié)計(jì))。 如果 capped 為 true,也需要指定該字段。 |
max | 數(shù)值 | (可選)指定固定集合中包含文檔的最大數(shù)量。 |
在插入文檔時(shí),MongoDB 首先檢查固定集合的 size 字段,然后檢查 max 字段。
1.1使用默認(rèn)集合
在 MongoDB 中,我們也可以不用創(chuàng)建集合,當(dāng)我們插入一些數(shù)據(jù)時(shí),會(huì)自動(dòng)創(chuàng)建集合, 并且會(huì)使用數(shù)據(jù)庫的名字作為集合的名稱。
創(chuàng)建一個(gè)新數(shù)據(jù)庫,名為 develop
如果開啟認(rèn)證,需要為新數(shù)據(jù)庫創(chuàng)建訪問用戶。新建用戶名為 itsxt,密碼為 itsxtpwd (注意:新建用戶要有userAdminAnyDatabase的權(quán)限)
使用 itsxt 用戶登錄 develop 庫
向 develop 庫中插入一條數(shù)據(jù)
查詢集合
1.2創(chuàng)建不帶參數(shù)的集合
我們也可以根據(jù)自己的情況創(chuàng)建集合。在 develop 數(shù)據(jù)庫中創(chuàng)建一個(gè)名為 dev 的集合, 該集合創(chuàng)建時(shí)不指定任何參數(shù)。如果開啟認(rèn)證,則需要使用具有數(shù)據(jù)庫管理員權(quán)限的用戶來 創(chuàng)建集合。
1.3創(chuàng)建帶參數(shù)的集合
在 develop 數(shù)據(jù)庫中創(chuàng)建一個(gè)名為 dev2 的固定集合,整個(gè)集合空間大小為 2000000kb, 文檔最大個(gè)數(shù)為 1000。
2 查看集合
如果要查看已有集合,可以使用 show collections 或 show tables 命令。
2.1show collections
2.2show tables
3 刪除集合
如果我們要?jiǎng)h除集合,需要先切換到需要?jiǎng)h除集合所在的數(shù)據(jù)庫,使用 drop()函數(shù)刪除 集合即可。
刪除集合的語法格式為:db.集合名稱.drop()。
刪除 dev2 集合
八、 MongoDB 的文檔操作
在 MongoDB 中文檔是指多個(gè)鍵及其關(guān)聯(lián)的值有序地放置在一起就是文檔,其實(shí)指的就是數(shù)據(jù),也是我們平時(shí)操作最多的部分。
MongoDB 中的文檔的數(shù)據(jù)結(jié)構(gòu)和 JSON 基本一樣。所有存儲(chǔ)在集合中的數(shù)據(jù)都是 BSON 格式。
BSON 是一種類似 JSON 的二進(jìn)制形式的存儲(chǔ)格式,是 Binary JSON 的簡稱。
1 插入文檔
1.1插入單個(gè)文檔
insert 函數(shù)
語法格式為:db.COLLECTION_NAME.insert(document)。
向 dev 集合中插入單個(gè)文檔。
{title:‘北京尚學(xué)堂’,description:‘程序員的搖籃’,url:‘www.bjsxt.com’,tags:[‘java’,'大數(shù)據(jù) ',‘python’]}
查看文檔
save 函數(shù)
向 dev 集合中插入單個(gè)文檔。
{title:‘百戰(zhàn)程序員’,description:‘身經(jīng)百戰(zhàn),高薪相伴’,url:‘www.itbaizhan.cn’,tags:[‘javaWeb 實(shí)戰(zhàn)’,‘?dāng)?shù)據(jù)庫實(shí)戰(zhàn)’,‘微服務(wù)實(shí)戰(zhàn)’]}
查看文檔
insertOne 函數(shù)
在 MongoDB3.2 以后的版本中,提供了 insertOne()函數(shù)用于插入文檔。
向 dev 集合中插入單個(gè)文檔。
{title:’ 尚學(xué)堂大數(shù)據(jù) ‘,description:’ 培養(yǎng)大數(shù)據(jù)人才的搖籃 ',url:‘www.bjsxt.com’,tags:[‘hadoop’,‘spark’,‘Hbase’]}
查看文檔
1.2插入多個(gè)文檔
向集合中批量插入多個(gè)文檔時(shí),需要使用數(shù)組來存放文檔。 語法格式:db.COLLECTION_NAME.insert([{},{},{}…])。
insert 或者 save 函數(shù)
向 dev 集合中批量插入多個(gè)文檔
[{title:‘java’,tags:[‘JavaSE’,‘JavaEE’,‘JavaME’]},{title:‘ORM’,tags:[‘Mybatis’,‘Hibernate’]},{title:‘Spring’,tags:[‘SpringMVC’,‘SpringBoot’,‘SpringCloud’]}]
查看文檔
insertMany 函數(shù)
在 MongoDB3.2 以后的版本中,提供了 insertMany 函數(shù)用于插入文檔。
語法格式:db.COLLECTION_NAME.insertMany([{},{},{},…])。
向 dev 集合中批量插入多個(gè)文檔[{title:‘Web’,tags:[‘JSP’,‘Servlet’]},{title:‘RPC’,tags:[‘RMI’,‘Dubbo’]},{title:‘DataBase’,tags:[‘Or acle’,‘MySQL’]}]
查看文檔
1.3通過變量插入文檔
Mongo Shell 工具允許我們定義變量。所有的變量類型為 var 類型。也可忽略變量類型。 變量中賦值符號后側(cè)需要使用小括號來表示變量中的值。我們可以將變量作為任意插入文檔 的函數(shù)的參數(shù)。
語法格式:變量名=({變量值})
通過變量插入單個(gè)文檔
定義變量
document=({title:‘SpringCloud’,tags:[‘Spring Cloud Netflix’,‘Spring Cloud Security’,‘Spring Cloud Consul’]})
插入文檔
查詢文檔
通過變量插入多個(gè)文檔
我們也可以在變量中定義多個(gè)文檔。
語法結(jié)構(gòu):變量名=([{},{},{},…])
插入文檔
我們現(xiàn)在將多個(gè)文檔放入到了一個(gè)變量中,所以在插入數(shù)據(jù)時(shí),可直接使用插入單個(gè)文檔的函數(shù)。
查詢文檔
2 更新文檔
MongoDB 通過 update 函數(shù)或者 save 函數(shù)來更新集合中的文檔。
2.1update 函數(shù)
update() 函數(shù)用于更新已存在的文檔。
語法格式:db.COLLECTION_NAME.update({查詢條件},{更新內(nèi)容},{更新參數(shù)(可選)})
將 Spring Data 修改為 SpringData
查看更新文檔
2.2更新操作符
$set 操作符
$set 操作符:用來指定一個(gè)鍵并更新鍵值,若鍵不存在并創(chuàng)建
語法格式:db.COLLECTION_NAME.update({查詢條件},{更新操作符:{更新內(nèi)容}})
將 Spring Security 修改為 SpringSecurity。
修改后的結(jié)果
使用$set 在 title 為 SpringData 的文檔中添加一個(gè)屬性為 num 值為 1。
批量更新
在更新文檔時(shí),可以使用 multi 參數(shù)實(shí)現(xiàn)批量更新。
添加測試數(shù)據(jù)
將 title 為 dev 的文檔的 size 更新為 500
查看結(jié)果
$inc 操作符
$inc 操作符:可以對文檔的某個(gè)值為數(shù)字型(只能為滿足要求的數(shù)字)的鍵進(jìn)行增減的操作。
將 title 為 SpringData 的文檔中的 num 值遞增 1。
查看結(jié)果
$unset 操作符
$unset 操作符:主要是用來刪除鍵。
刪除 title 為 SpringData 的文檔中的 num 鍵。
查看結(jié)果
$push 操作符
$push 操作符:向文檔的某個(gè)數(shù)組類型的鍵添加一個(gè)數(shù)組元素,不過濾重復(fù)的數(shù)據(jù)。添加時(shí)鍵存在,要求鍵值類型必須是數(shù)組;鍵不存在,則創(chuàng)建數(shù)組類型的鍵。
向 title 為 SpringData 的文檔中添加一個(gè)數(shù)組鍵為 tags 值為[“Spirng Data Redis”]
查看結(jié)果
$pop 操作符
$pop 操作符:刪除數(shù)據(jù)元素。
1 表示從數(shù)組的尾部刪除
刪除 title 為 Spring 的文檔中 tags 數(shù)組中的 Spring Cloud
查看結(jié)果
-1 表示從數(shù)組的頭部刪除元素
刪除 title 為 Spring 的文檔中 tags 數(shù)組中的 SpringMVC
查看結(jié)果
$pull 操作符
$pull 操作符:從數(shù)組中刪除滿足條件的元素
刪除 title 為 Spring 的文檔中 tags 數(shù)組中的 SpringBoot
查看結(jié)果
$pullAll 操作符
$pullAll 操作符:從數(shù)組中刪除滿足條件的多個(gè)元素
刪除 title 為 java 的文檔中 tags 數(shù)組中的 JavaSE、JavaEE
查看結(jié)果
$rename
$rename 操作符:對鍵進(jìn)行重新命名。
將 title 為 Java 的文檔中的 tags 鍵修改為 tag。
查看結(jié)果
2.3使用 save()函數(shù)更新文檔
save() 方法通過傳入的文檔來替換已有文檔。
語法格式:save({文檔})
更新 title 為 SpringData 的文檔,將 SpringData 修改為 Spring Data,并去掉 tags
查看結(jié)果
3 刪除文檔
3.1remove()函數(shù)
使用 remove()函數(shù)可刪除集合中的指定文檔。
語法格式:remove({指定刪除條件},刪除參數(shù)(可選參數(shù)))
刪除 title 為 Spring data 的文檔,可使用該文檔的 ObjectId 作為刪除條件
如果使用的條件在集合中可以匹配多條數(shù)據(jù),那么 remove()函數(shù)會(huì)刪除所有滿足條件的 數(shù)據(jù)。我們可以在 remove 函數(shù)中給定 justOne,表示只刪除第一條,在 remove 函數(shù)中給定 參數(shù) 1 即可。
向 dev 集合中插入三條擁有相同 title 的測試數(shù)據(jù)
查看結(jié)果
只刪除第一條數(shù)據(jù)
查看結(jié)果
注意:remove() 方法 并不會(huì)真正釋放空間。需要繼續(xù)執(zhí)行 db.repairDatabase() 來回收 磁盤空間。
3.2deleteOne()函數(shù)
deleteOne()函數(shù)是官方推薦刪除文檔的方法。該方法只刪除滿足條件的第一條文檔。
查看結(jié)果
3.3deleteMany()函數(shù)
deleteMany 函數(shù)是官方推薦的刪除方法。該方法刪除滿足條件的所有數(shù)據(jù)。
再次插入兩條測試數(shù)據(jù)
查看結(jié)果
刪除所有 title 為 dev 的文檔
3.4刪除集合中的所有文檔
使用 remove 函數(shù)刪除集合中的所有文檔
語法格式:remove({})
使用 deleteMany 函數(shù)刪除所有文檔
語法格式:deleteMany({})
4 查詢文檔
4.1find()函數(shù)
在 MongoDB 中可以使用 find()函數(shù)查詢文檔。
語法格式為:find({查詢條件(可選)},{指定投影的鍵(可選)})
如果未給定參數(shù)則表示查詢所有數(shù)據(jù)。
pretty()函數(shù)可以使用格式化的方式來顯示所有文檔。
查詢 dev 集合中的所有數(shù)據(jù)并格式化顯示。
查詢 title 為 DataBase 的文檔并格式化顯示。
4.2findOne()函數(shù)
findOne()函數(shù)只返回滿足條件的第一條數(shù)據(jù)。如果未做投影操作該方法則自帶格式化功 能。
語法格式:findOne({查詢條件(可選)},{投影操作(可選)})
插入三條測試數(shù)據(jù)
使用 findOne 查詢文檔,條件為 title 的值為 dev 的文檔。
4.3模糊查詢
在 MongoDB 中可以通過 // 與 ^ $ 實(shí)現(xiàn)模糊查詢,注意使用模糊查詢時(shí)查詢條件不能放到雙引號或單引號中。
查詢文檔中 title 的值含有 a 的內(nèi)容。
使用^表示起始位置。
查詢文檔中 title 的值以 S 開頭的內(nèi)容。
使用$表示結(jié)尾位置。
查詢文檔中 title 的值以g結(jié)尾的內(nèi)容。
4.4投影操作
find()函數(shù)投影操作
在 find 函數(shù)中我們可以指定投影鍵。
語法格式為:find({查詢條件},{投影鍵名:1(顯示該列)|0(不顯示該列),投影鍵名:1|0,…})
_id 列默認(rèn)為顯示列。如果不顯示_id 可在投影中通過 0 過濾。
findOne 函數(shù)投影操作
在 findOne 函數(shù)中我們可以指定投影列。
語法格式為:findOne({查詢條件},{投影鍵名:1(顯示該列)|0(不顯示該列)})
5 條件操作符
條件操作符用于比較兩個(gè)表達(dá)式并從 mongoDB 集合中獲取數(shù)據(jù)。
語法格式:find({鍵:{操作符:條件}})或者 findOne({鍵:{操作符:條件}})
5.1$gt
(>) 大于操作符
我們可以使用$gt 操作做大于的條件判斷。該操作符可以數(shù)字或日期進(jìn)行判斷。
添加測試數(shù)據(jù)。
查詢 size 大于 300 的文檔。
5.2$lt
(<) 小于操作符
我們可以使用$lt 操作做小于的條件判斷。該操作符可以數(shù)字或日期進(jìn)行判斷。
查詢 size 小于 300 的文檔。
5.3$gte
(>=)大于或等于操作符
我們可以使用$gte 操作做大于或等于的條件判斷。該操作符可以數(shù)字或日期進(jìn)行判斷。
查詢 size 大于或等于 300 的文檔。
5.4$lte
(<=)小于或等于操作符
我們可以使用$lte 操作做小于或等于的條件判斷。該操作符可以數(shù)字或日期進(jìn)行判斷。
查詢 size 小于或等于 300 的文檔。
5.5$eq
(==)等于操作符
我們可以使用$eq 操作做相等的條件判斷。
查詢 size 等于 300 的文檔。
5.6$ne
(!=)不等操作符
我們可以使用$ne 操作做不等的條件判斷。
查詢 size 不等于 300 的文檔。
5.7$and
我們可以使用$and 操作符來表示多條件間的并且關(guān)系。
語法格式為:find({$and:[{條件一},{,條件二},…]})
插入測試數(shù)據(jù)
如果在查詢中給定了多個(gè)查詢條件,條件之間的關(guān)系默認(rèn)為 and 關(guān)系。
查詢 size 大于 100 并且小于 300 的文檔。
使用$and 指定多條件關(guān)系。
查詢 size 大于 100 并且小于 300 的文檔。
5.8$or
我們可以使用$or 操作符來表示多條件間的或者關(guān)系。
語法格式為:find({$or:[{條件一},{條件二},…]})
查詢 title 的值為 test2 或者 size 大于 300 的文檔。
5.9$and 與$or 聯(lián)合使用
查詢 title 為 test5 并且 size 等于 500,或者 size 小于 400 的文檔。
5.10$type 操作符
$type 操作符是基于 BSON 類型來檢索集合中匹配的數(shù)據(jù)類型,并返回結(jié)果。
插入測試數(shù)據(jù)
查詢 title 的值為 number 類型。
6 Limit 函數(shù)與 Skip 函數(shù)
6.1Limit 函數(shù)
如果需要在 MongoDB 中讀取指定數(shù)量的數(shù)據(jù)記錄,可以使用 MongoDB 的 Limit 函數(shù), limit()函數(shù)接受一個(gè)數(shù)字參數(shù),該參數(shù)指定從 MongoDB 中讀取的記錄條數(shù)。
語法格式:db.COLLECTION_NAME.find().limit(NUMBER)
6.2Skip 函數(shù)
我們除了可以使用 limit()函數(shù)來讀取指定數(shù)量的數(shù)據(jù)外,還可以使用 skip()函數(shù)來跳過指定數(shù)量的數(shù)據(jù),skip 函數(shù)同樣接受一個(gè)數(shù)字參數(shù)作為跳過的記錄條數(shù)。
語法格式:db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
我們可以使用 skip 函數(shù)與 limit 函數(shù)實(shí)現(xiàn) MongoDB 的分頁查詢,但是官方并不推薦這樣做,因?yàn)闀?huì)掃描全部文檔然后在返回結(jié)果,效率過低。
7 MongoDB 排序
在 MongoDB 中使用 sort() 函數(shù)對查詢到的文檔進(jìn)行排序,sort() 函數(shù)可以通過參數(shù) 指定排序的字段,并使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而 -1 是用于 降序排列。
語法格式:db.COLLECTION_NAME.find().sort({排序鍵:1})
7.1升序排序
查詢 size 的值為 number 類型的文檔,顯示 title,size 的內(nèi)容,并對 size 做升序排序。
7.2降序排序
查詢 size 的值為 number 類型的文檔,顯示 title,size 的內(nèi)容,并對 size 做降序排序。
7.3對字符串排序
對字符串排序的方式采用的是大小寫分離排序。
8 MongoDB 索引
索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB 在讀取數(shù)據(jù)時(shí)必須掃描集合中的每個(gè)文件并選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是非常低的,特別在處理大量的數(shù)據(jù)時(shí),查詢可能要花費(fèi)幾十秒甚至幾分鐘,這對系統(tǒng)的性能是非常致命的。索引是特殊的數(shù)據(jù)結(jié)構(gòu),索引存儲(chǔ)在一個(gè)易于遍歷讀取的數(shù)據(jù)集合中,索引是對數(shù)據(jù)庫表中一列或多列的值進(jìn)行排序的一種結(jié)構(gòu)
8.1創(chuàng)建索引
在 MongoDB 中會(huì)自動(dòng)為文檔中的_Id(文檔的主鍵)鍵創(chuàng)建索引,與關(guān)系型數(shù)據(jù)的主鍵索引類似。
我們可以使用 createIndex()函數(shù)來為其他的鍵創(chuàng)建索引。在創(chuàng)建索引時(shí)需要指定排序規(guī)則。1 按照升序規(guī)則創(chuàng)建索引,-1 按照降序規(guī)則創(chuàng)建索引。
在創(chuàng)建索引時(shí),需要使用具有 dbAdmin 或者 dbAdminAnyDatabase 角色的用戶。
語法格式:db.COLLECTION_NAME.createIndex({創(chuàng)建索引的鍵:排序規(guī)則,…},{創(chuàng)建索 引的參數(shù)(可選參數(shù))})
參數(shù)說明
為 dev 集合中的 title 鍵創(chuàng)建索引,并讓創(chuàng)建工作在后臺(tái)運(yùn)行。
8.2查看索引
查看集合索引
我們可以通過 getIndexes()或者 getIndexSpecs()函數(shù)查看集合中的所有索引信息。
語法格式:db.COLLECTION_NAME.getIndexes()
語法格式:db.COLLECTION_NAME.getIndexSpecs()
使用 getIndexes()函數(shù)查看當(dāng)前 dev 集合中的索引
使用 getIndexSpecs()函數(shù)查看當(dāng)前 dev 集合中的索引
查看索引鍵
我們可以通過使用 getIndexKeys()函數(shù)查看集合的索引鍵。
語法格式:db.COLLECTION_NAME.getIndexKeys();
查看 dev 集合中的索引鍵
查看索引大小
我們可以通過 totalIndexSize()函數(shù)來查看當(dāng)前集合中索引的大小,單位為字節(jié)。
語法格式:db.COLLECTION_NAME.totalIndexSize([detail] (可選參數(shù)) )
參數(shù)解釋:detail 可選參數(shù),傳入除 0 或 false 外的任意數(shù)據(jù),那么會(huì)顯示該集合中每個(gè) 索引的大小及集合中索引的總大小。如果傳入 0 或 false 則只顯示該集合中所有索引的總大 小。默認(rèn)值為 false。
查看 dev 集合中所有索引的總大小。
查看 dev 集合中的每個(gè)索引的大小以及總大小
8.3修改索引
MongoDB 沒有單獨(dú)的修改索引函數(shù),如果要修改某個(gè)索引,需要先刪除舊的索引,再創(chuàng)建新的索引。
8.4刪除索引
刪除集合中的指定索引
我們可以通過 dropIndex()函數(shù)來刪除指定索引。
語法格式:db.COLLECTION_NAME.dropIndex(“索引名稱”)。
刪除 title 鍵的索引
刪除集合中的全部索引
我們可以使用 dropIndexes()函數(shù)刪除集合中的全部索引,_id 鍵的索引除外。
語法格式:db.COLLECTION_NAME.dropIndexes()
8.5重建索引
我可以使用 reIndex()函數(shù)重建索引。重建索引可以減少索引存儲(chǔ)空間,減少索引碎片,優(yōu)化索引查詢效率。一般在數(shù)據(jù)大量變化后,會(huì)使用重建索引來提升索引性能。重建索引是刪除原索引重新創(chuàng)建的過程,不建議反復(fù)使用。
語法格式:db.COLLECTION_NAME.reIndex()
8.6MongoDB中的索引類型
在 MongoDB 中支持多種類型的索引,包括單字段索引、復(fù)合索引、多 key 索引、文本索引等,每種類型的索引有不同的使用場合。
單字段索引(Single Field Index)
所謂單字段索引是指在索引中只包含了一個(gè)鍵。查詢時(shí),可加速對該字段的各種查詢請求,是最常見的索引形式。MongoDB 默認(rèn)創(chuàng)建的_Id 索引也是這種類型。我們可以使用 createIndex({索引鍵:排序規(guī)則})函數(shù)來創(chuàng)建單字段索引。
語法格式:db.COLLECTION_NAME.createIndex({索引鍵名:排序規(guī)則})
為 dev 集合中的 title 鍵創(chuàng)建單字段索引
交叉索引
所謂交叉索引就是為一個(gè)集合的多個(gè)字段分別建立索引,在查詢的時(shí)候通過多個(gè)字段作為查詢條件,這種情況稱為交叉索引。
在查詢文檔時(shí),在查詢條件中包含一個(gè)交叉索引鍵或者在一次查詢中使用多個(gè)交叉索引鍵作為查詢條件都會(huì)觸發(fā)交叉索引。
為 dev 集合中的 size 鍵創(chuàng)建交叉索引。
復(fù)合索引(Compound Index)
復(fù)合索引是 Single Field Index 的升級版本,它針對多個(gè)字段聯(lián)合創(chuàng)建索引,先按第一個(gè)字段排序,第一個(gè)字段相同的文檔按第二個(gè)字段排序,依次類推。
語法格式:db.COLLECTION_NAME.createIndex({索引鍵名:排序規(guī)則, 索引鍵名:排序規(guī)則,…});
復(fù)合索引能滿足的查詢場景比單字段索引更豐富,不光能滿足多個(gè)字段組合起來的查詢,也能滿足所以能匹配符合索引前綴的查詢。
刪除 dev 中的交叉索引。
創(chuàng)建 title 與 size 的復(fù)合索引
查看索引
多 key 索引 (Multikey Index)
當(dāng)索引的字段為數(shù)組時(shí),創(chuàng)建出的索引稱為多 key 索引,多 key 索引會(huì)為數(shù)組的每個(gè)元素建立一條索引。
語法格式:db.COLLECTION_NAME.createIndex({數(shù)組鍵名:排序規(guī)則});
為 dev 集合中 tags 鍵創(chuàng)建多 Key 索引
查看索引
8.7索引額外屬性
MongoDB 除了支持多種不同類型的索引,還能對索引定制一些特殊的屬性。
唯一索引 (unique index)
唯一索引會(huì)保證索引對應(yīng)的鍵不會(huì)出現(xiàn)相同的值,比如_id 索引就是唯一索引
語法格式:db.COLLECTION_NAME.createIndex({索引鍵名:排序規(guī)則},{unique:true})
如果唯一索引所在字段有重復(fù)數(shù)據(jù)寫入時(shí),拋出異常。
刪除 dev 集合中的索引。為 dev 集合中的 title 鍵建立唯一索引
插入 title 相同的值測試唯一索引
部分索引 (partial index)
部分索引是只針對符合某個(gè)特定條件的文檔建立索引,3.2 版本才支持該特性。
MongoDB 部分索引只為那些在一個(gè)集合中,滿足指定的篩選條件的文檔創(chuàng)建索引。由于部分索引是一個(gè)集合文檔的一個(gè)子集,因此部分索引具有較低的存儲(chǔ)需求,并降低了索引創(chuàng)建和維護(hù)的性能成本。部分索引通過指定過濾條件來創(chuàng)建,可以為 MongoDB 支持的所有索引類型使用部分索引。
簡單點(diǎn)說:部分索引就是帶有過濾條件的索引,即索引只存在與某些文檔之上
語 法 格 式 : db.COLLECTION_NAME.createIndex({ 索引鍵名 : 排 序 規(guī) 則},{partialFilterExpression:{鍵名:{匹配條件:條件值}}})
為 dev 集合中的 size 鍵創(chuàng)建部分索引。條件為大于 300
查看索引
注意:部分索引只為集合中那些滿足指定的篩選條件的文檔創(chuàng)建索引。如果你指定的 partialFilterExpression 和唯一約束、那么唯一性約束只適用于滿足篩選條件的文檔。具有唯 一約束的部分索引不會(huì)阻止不符合唯一約束且不符合過濾條件的文檔的插入。
稀疏索引(sparse index)
稀疏索引僅包含具有索引字段的文檔的條目,即使索引字段包含空值也是如此。索引會(huì)跳過缺少索引字段的任何文檔。索引是“稀疏的”,因?yàn)樗话系乃形臋n。相反,非稀疏索引包含集合中的所有文檔,為那些不包含索引字段的文檔存儲(chǔ)空值。
語法格式:db.COLLECTION_NAME.createIndex({索引鍵名:排序規(guī)則},{sparse:true})
為 dev 集合中的 tag 鍵創(chuàng)建稀疏索引
查看索引
注意:從 MongoDB 3.2 開始,MongoDB 提供了創(chuàng)建部分索引的選項(xiàng) 。部分索引提供了稀疏索引功能的超集。如果您使用的是 MongoDB 3.2 或更高版本,則部分索引應(yīng)優(yōu)先于稀疏索引
8.8覆蓋索引查詢
官方的 MongoDB 的文檔中說明,覆蓋查詢是以下的查詢:
- 所有的查詢字段是索引的一部分
- 所有的查詢返回字段在同一個(gè)索引中
由于所有出現(xiàn)在查詢中的字段是索引的一部分, MongoDB 無需在整個(gè)數(shù)據(jù)文檔中檢索匹配查詢條件和返回使用相同索引的查詢結(jié)果。
因?yàn)樗饕嬖谟?RAM 中,從索引中獲取數(shù)據(jù)比通過掃描文檔讀取數(shù)據(jù)要快得多。
如有如下索引:
db.stu.createIndex({title:1,:size:1})
那么執(zhí)行如下查詢時(shí),該索引會(huì)覆蓋查詢:
db.stu.find({title:“dev”},{size:1,_id:0})
也就是說,對于上述查詢,MongoDB 的不會(huì)去數(shù)據(jù)庫文件中查找。相反,它會(huì)從索引中提取數(shù)據(jù),這是非常快速的數(shù)據(jù)查詢。
由于我們的索引中不包括 _id 字段,_id 在查詢中會(huì)默認(rèn)返回,我們可以在 MongoDB 的查詢結(jié)果集中排除它。
8.9查詢計(jì)劃
在 MongoDB 中通過 explain()函數(shù)啟動(dòng)執(zhí)行計(jì)劃,我們可以使用查詢計(jì)劃分析索引的使用情況,可通過查看詳細(xì)的查詢計(jì)劃來決定如何優(yōu)化。
語法結(jié)構(gòu):db.COLLECTION_NAME.find().explain()
刪除 dev 集合中的所有索引。通過查詢計(jì)劃查看查詢 size 鍵的值大于 200 的查詢結(jié)果
為 size 鍵創(chuàng)建單字段索引。再次查看查詢結(jié)果。
創(chuàng)建索引
查看執(zhí)行結(jié)果
8.10使用索引注意事項(xiàng)
既然索引可以加快查詢速度,那么是不是只要是查詢語句,就創(chuàng)建索引呢?答案是否定的。因?yàn)樗饕m然加快了查詢速度,但索引也是有代價(jià)的:索引文件本身要消耗存儲(chǔ)空間, 同時(shí)索引會(huì)加重插入、刪除和修改記錄時(shí)的負(fù)擔(dān),另外,數(shù)據(jù)庫在運(yùn)行時(shí)也要消耗資源維護(hù)索引,因此索引并不是越多越好。
那么什么情況不建議創(chuàng)建索引呢?例如一兩千條甚至只有幾百條記錄的表,沒必要建索引,讓查詢做全集合掃描就好了。至于多少條記錄才算多?我個(gè)人建議以 2000 作為分界線, 記錄數(shù)不超過 2000 可以考慮不建索引,超過 2000 條可以酌情考慮創(chuàng)建索引。
如何創(chuàng)建合適的索引
- 建立合適的索引
為每一個(gè)常用查詢結(jié)構(gòu)建立合適的索引。
復(fù)合索引是創(chuàng)建的索引由多個(gè)字段組成,例如:
db.test.createIndex({“username”:1, “age”:-1})
交叉索引是每個(gè)字段單獨(dú)建立索引,但是在查詢的時(shí)候組合查找,例如:
db.test.createIndex({“username”:1})
db.test.createIndex({“age”:-1})
db.test.find({“username”:“kaka”, “age”: 30})
交叉索引的查詢效率較低,在使用時(shí),當(dāng)查詢使用到多個(gè)字段的時(shí)候,盡量使用復(fù)合索引,而不是交叉索引。
- 復(fù)合索引的字段排列順序
當(dāng)我們的組合索引內(nèi)容包含匹配條件以及范圍條件的時(shí)候,比如包含用戶名(匹配條件)以及年齡(范圍條件),那么匹配條件應(yīng)該放在范圍條件之前。
比如需要查詢:
db.test.find({“username”:“kaka”, “age”: {$gt: 30}})
那么復(fù)合索引應(yīng)該這樣創(chuàng)建:
db.test.ensureIndex({“username”:1, “age”:-1})
查詢時(shí)盡可能僅查詢出索引字段
有時(shí)候僅需要查詢少部分的字段內(nèi)容,而且這部分內(nèi)容剛好都建立了索引,那么盡可能只查詢出這些索引內(nèi)容,需要用到的字段顯式聲明(_id 字段需要顯式忽略!)。因?yàn)檫@些 數(shù)據(jù)需要把原始數(shù)據(jù)文檔從磁盤讀入內(nèi)存,造成一定的損耗。
比如說我們的表有三個(gè)字段:
name, age, mobile
索引是這樣建立的:
db.stu.createIndex({“name”:1,“age”:-1})
我們僅需要查到某個(gè)用戶的年齡(age),那可以這樣寫:
db.stu.find({“name”:“kaka”}, {“_id”:0, “age”:1})
注意到上面的語句,我們除了”age”:1 外,還加了”_id”:0,因?yàn)槟J(rèn)情況下,_id 都是會(huì)被一并查詢出來的,當(dāng)不需要_id 的時(shí)候記得直接忽略,避免不必要的磁盤操作。
對現(xiàn)有的數(shù)據(jù)大表建立索引的時(shí)候,采用后臺(tái)運(yùn)行方式
在對數(shù)據(jù)集合建立索引的過程中,數(shù)據(jù)庫會(huì)停止該集合的所有讀寫操作,因此如果建立 索引的數(shù)據(jù)量大,建立過程慢的情況下,建議采用后臺(tái)運(yùn)行的方式,避免影響正常業(yè)務(wù)流程。
db.stu.ensureIndex({“name”:1,“age”:-1},{“background”:true})
8.11索引限制
額外開銷
每個(gè)索引占據(jù)一定的存儲(chǔ)空間,在進(jìn)行插入,更新和刪除操作時(shí)也需要對索引進(jìn)行操作。 所以,如果你很少對集合進(jìn)行讀取操作,建議不使用索引。
內(nèi)存使用
由于索引是存儲(chǔ)在內(nèi)存(RAM)中,你應(yīng)該確保該索引的大小不超過內(nèi)存的限制。 如果索引的大小大于內(nèi)存的限制,MongoDB 會(huì)刪除一些索引,這將導(dǎo)致性能下降。
查詢限制
索引不能被以下的查詢使用:
正則表達(dá)式(最左匹配除外)及非操作符,如 $nin, $not, 等。
算術(shù)運(yùn)算符,如 $mod, 等。
所以,檢測你的語句是否使用索引是一個(gè)好的習(xí)慣,可以用 explain 來查看。
最大范圍
集合中索引不能超過 64 個(gè)
索引名的長度不能超過 128 個(gè)字符
一個(gè)復(fù)合索引最多可以有 31 個(gè)字段
8.12正則查詢
MongoDB 中查詢條件也可以使用正則表達(dá)式作為匹配約束。
語法格式:
db.COLLECTION_NAME.find({字段名:正則表達(dá)式});
或
db.COLLECTION_NAME.find({字段名:{$regex:正則表達(dá)式,$options:正則選項(xiàng)}});
正則表達(dá)式格式:/xxx/
正則選項(xiàng):
i - 不區(qū)分大小寫以匹配大小寫的情況。
m - 多行查找,如果內(nèi)容里面不存在換行符號(例如 \n)或者條件上沒有(start/end), 該選項(xiàng)沒有任何效果
x - 設(shè)置 x 選項(xiàng)后,正則表達(dá)式中的非轉(zhuǎn)義的空白字符將被忽略。需要$regex 與$options 語法
s - 允許點(diǎn)字符(即.)匹配包括換行符在內(nèi)的所有字符。需要$regex 與$options 語法 i,m,x,s 可以組合使用。
查詢 dev 集合中 title 字段以’S’開頭的數(shù)據(jù)
db.dev.find({title:/^S/})
db.dev.find({title:{$regex:/^S/}})
查詢 dev 集合中 title 字段以’g’結(jié)尾的數(shù)據(jù)
db.stu.find({title:/g$/})
db.stu.find({title:{$regex:/g$/}});
查詢 dev 集合中 dev 字段中包含’ing’的數(shù)據(jù)
db.stu.find({title:/ing/});
db.stu.find({title:{$regex:/ing/}});
查詢 dev 集合中 title 字段以’S’開頭的數(shù)據(jù),且忽略大小寫
db.dev.find({title:/^S/i});
db.dev.find({title:{$regex:/^S/i}});
db.dev.find({title:{$regex:/^S/, $options:“i”}});
查詢 dev 集合中 title 字段已’S’開頭、'g’結(jié)尾的數(shù)據(jù)
db.dev.find({title:/^S.*g$/});
db.dev.find({title:{$regex:/^S.*n$/}});
查詢 dev 集合中 title 字段以’S’或’t’開頭的數(shù)據(jù)
db.dev.find({title:{$in:[/^S/, /^t/]}});
查詢 dev 集合中 title 字段不以’S’開頭的數(shù)據(jù)
db.dev.find({title:{$not:/^S/}});
查詢 dev 集合中 title 字段不以’S’或’t’開頭的數(shù)據(jù)
db.stu.find({title:{$nin:[/^S/, /^t/]}});
9 MongoDB 聚合查詢
在 MongoDB 中我們可以通過 aggregate()函數(shù)來完成一些聚合查詢,aggregate()函數(shù)主 要用于處理諸如統(tǒng)計(jì),平均值,求和等,并返回計(jì)算后的數(shù)據(jù)結(jié)果。
語法格式:
db.COLLECTION_NAME.aggregate([{$group:{_id:“$分組鍵名”,“$分組鍵名”,…,別名:{聚合 運(yùn)算:“$運(yùn)算列”}}},{條件篩選:{鍵名:{運(yùn)算條件:運(yùn)算值}}}])
常見的 mongo 的聚合操作和 mysql 的查詢做類比
9.1求和 - $sum
查詢 dev 集合中一共有多少個(gè)文檔。
相當(dāng)于 sql 語句:SELECT count(*) AS count FROM dev
db.dev.aggregate([{$group:{_id:null,count:{$sum:1}}}])
$group:分組,代表聚合的分組條件
_id:分組的字段。相當(dāng)于 SQL 分組語法 group by column_name 中的 column_name 部分。 如果根據(jù)某字段的值分組,則定義為_id:‘$字段名’。所以此案例中的 null 代表一個(gè)固定的字面值’null’。
count:返回結(jié)果字段名??梢宰远x,類似 SQL 中的字段別名。
$sum:求和表達(dá)式。相當(dāng)于 SQL 中的 sum()。
1:累加值。
查詢 dev 集合中的所有 size 鍵中的值的總和。
相當(dāng)于 sql 語句:SELECT sum(size) AS totalSize FROM dev
db.dev.aggregate([{$group:{_id:null,totalSize:{$sum:“$size”}}}])
“$size”:代表文檔中的 szie 字段的值。
對每一個(gè) title 進(jìn)行分組并計(jì)算每組中的 size 的總和
相當(dāng)于 sql 語句:SELECT title AS _id , sum(size) AS totalSize FROM dev GROUP BY title
db.dev.aggregate([{$group:{_id:“$title”,totalSize:{$sum:“$size”}}}])
9.2條件篩選 - $match
查詢 dev 集合有多少文檔的 size 大于 200。
db.dev.aggregate([{$match:{size:{$gt:200}}},{$group:{_id:null,totalSize:{$sum:1}}}])
相當(dāng)于 SQL 語句:SELECT count(*) FROM dev WHERE size > 200
$match:匹配條件,相當(dāng)于 SQL 中的 where 子句,代表聚合之前進(jìn)行條件篩選。
查詢 dev 集合,根據(jù) title 分組計(jì)算出每組的 size 的總和,并過濾掉總和小于等于 200 的文檔。
db.dev.aggregate([{$group:{_id:“$title”,totalSize:{$sum:“$size”}}},{$match:{totalSize:{$gt: 200}}}])
相當(dāng)于 SQL 語句:SELECT sum(size) AS totalSize FROM dev GROUP BY title HAVING totalSize > 200
9.3最大值 - $max
查詢 dev 集合中 size 最大的文檔。
db.dev.aggregate([{$group:{_id:null,maxSize:{$max:“$size”}}}])
$max:“$size”:計(jì)算 size 鍵中的最大值。
相當(dāng)于 SQL 語句:SELECT max(size) FROM dev
9.4最小值 - $min
查詢 dev 集合中 size 最小的文檔。
db.dev.aggregate([{$group:{_id:null,minSize:{$min:“$size”}}}])
$min:“$size”:計(jì)算 size 鍵中的最小值。
相當(dāng)于 SQL 語句:SELECT min(size) FROM dev
9.5平均值 - $avg
查詢 dev 集合中 size 的平均值
db.dev.aggregate([{$group:{_id:null,sizeAvg:{$avg:“$size”}}}])
$avg:“$size”:計(jì)算 size 鍵的平均值。
相當(dāng)于 SQL 語句:SELECT avg(size) FROM dev
9.6統(tǒng)計(jì)結(jié)果返回?cái)?shù)組 - $push
查詢 dev 集合,按照 size 分組并返回他們的 title,如果 size 相同則使用數(shù)組返回他們的 title。
db.dev.aggregate([{$group:{_id:“$size”,title:{$push:“$title”}}}])
$push:“$title”:如果 size 相同則使用數(shù)組返回他們不同的 title
9.7數(shù)組字段拆分 - $unwind
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。
db.dev.aggregate([{$unwind:“$tags”}])
$unwind:“$tags”:對數(shù)組中的元素進(jìn)行拆分顯示。
9.8管道操作
什么是管道操作:
管道在 Unix 和 Linux 中一般用于將當(dāng)前命令的輸出結(jié)果作為下一個(gè)命令的參數(shù)。
MongoDB 的聚合管道將 MongoDB 文檔在一個(gè)管道處理完畢后將結(jié)果傳遞給下一個(gè)管 道處理。管道操作是可以重復(fù)的。
管道操作符是按照書寫的順序依次執(zhí)行的,每個(gè)操作符都會(huì)接受一連串的文檔,對這些文檔做一些類型轉(zhuǎn)換,最后將轉(zhuǎn)換后的文檔作為結(jié)果傳遞給下一個(gè)操作符(對于最后一個(gè)管道操作符,是將結(jié)果返回給客戶端),稱為流式工作方式。
管道操作符:$match、$group、$sort、$limit、$skip、$unwind
管道操作符,只能用于計(jì)算當(dāng)前聚合管道的文檔,不能處理其它的文檔。
$project-聚合投影約束
$project 操作符:我們可以使用$project 操作符做聚合投影操作。
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示,并只顯示 title 鍵與 tags 鍵的值。
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,tags:“$tags”,title:“$title”}}])
tags:“$tags”:顯示 tags 的值,字段名為 tags。
title:“$title”:顯示 title 的值,字段名為 title。
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。要求只顯示 title 鍵與 tags 鍵的值并將 title 鍵修改為 Title。
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,tags:“$tags”,Title:“$title”}}])
Title:“$title”:顯示 title 的值,字段名為 Title。
$project-字符串處理
在$project 中我們可以通過 MongoDB 的字符串操作符對投影的內(nèi)容做字符串處理。
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。將 title 中的值換為小寫并命名為 New_Title, 將 tags 的值轉(zhuǎn)換為大寫并命名為 New_Tags。
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,New_Title:{$toLower:“$title”},New_ tags:{$toUpper:“$tags”}}}])
New_Title:{$toLower:“$title”}:將 title 的值轉(zhuǎn)換為小寫,顯示字段名為 New_Title。
New_tags:{$toUpper:“$tags”}:將 tags 的值轉(zhuǎn)換為大寫,顯示字段名為 New_Tags。
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。將 title 字段和 tags 字段的值拼接為一個(gè)完整字符串并在 Title_Tags 字段中顯示。
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,Title_Tags:{$concat:[“$title”,“-”,“$tag s”]}}}])
Title_Tags:{$concat:[“$title”,“-”,“$tags”]}:將字段 title 與字符串’-'和字段 tags 的值拼接為新的字符串,并顯示字段名為 Title_Tags
查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。只顯示 title 字段的前 3 個(gè)字符,并命名為 Title_Prefix
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,Title_Prefix:{$substr:[“$title”,0,3]}}} ])
Title_Prefix:{$substr:[“$title”,0,3]}:將 title 的值從0 開始截取截3 位,并命名為 Title_Prefix
我們可以看到對于漢字部分并未截取三位,原因是$substr 只能匹配 ASCII 的數(shù)據(jù),對 于中文要使用$substrCP
$project-算術(shù)運(yùn)算
在$project 中我們可以通過 MongoDB 的算數(shù)作符對投影的內(nèi)容做運(yùn)算處理。
查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做加 1 操作,顯示字段 命名為 New_Size。
db.dev.aggregate([{$project:{_id:0,title:1,New_Size:{$add:[“$size”,1]}}}])
New_Size:{$add:[“$size”,1]}:在查詢結(jié)果中,對size的值做加1處理,并命名為New_Size。
排除那些沒有 size 鍵的文檔。
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$add:[“$size”,1]}}}])
$match:{size:{$ne:null}:排除那些沒有 size 的文檔。
查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做減 1 操作,顯示字段 命名為 New_Size。
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$subtract:[ “$size”,1]}}}])
New_Size:{$subtract:[“$size”,1]}:在查詢結(jié)果中,對 size 的值做減 1 處理,并命名為 New_Size。
查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做乘 2 操作,顯示字段 命名為 New_Size。
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$multiply: [“$size”,2]}}}])
New_Size:{$multiply:[“$size”,2]}:在查詢結(jié)果中,對 size 的值做乘 2 處理,并命名為 New_Size.
查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做除 2 操作,顯示字段 命名為 New_Size。
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$divide:[" $size",2]}}}])
New_Size:{$divide:[“$size”,2]}:在查詢結(jié)果中,對 size 的值做除 2 處理,并命名為 New_Size.
查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做模 2 操作,顯示字段 命名為 New_Size。
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$mod:[“$size”,2]}}}])
New_Size:{$mod:[“$size”,2]}:在查詢結(jié)果中,對size的值做模2處理,并命名為New_Size.
$project-日期操作
插入當(dāng)前時(shí)間 db.dev.insert({date:new Date()})
MongoDB 中的時(shí)間會(huì)比系統(tǒng)當(dāng)前時(shí)間少 8 個(gè)小時(shí)。因?yàn)樗臅r(shí)間是 UTC 的時(shí)間,而中 國的時(shí)區(qū)是東八區(qū),比 UTC 快 8 個(gè)小時(shí),所以會(huì)比當(dāng)前時(shí)間少 8 個(gè)小時(shí)。
插入指定日期
方式一:
db.dev.insert({time:new Date(“2018-05-01T14:20:23Z”)})
new Date(“2018-05-01T14:20:23Z”):創(chuàng)建時(shí)間對象,日期格式為 yyyy-MM-ddThh:mm:ssZ
方式二:
db.dev.insert({time:ISODate(“2019-06-01T16:30:00Z”)})
ISODate(“2019-06-01T16:30:00Z”):
查詢時(shí)間
db.dev.find({time:{$eq:new Date(“2018-05-01T14:20:23”)}})
或者
db.dev.find({time:{$gt:new Date(“2018-04-01”)}})
或者
向 dev 集合中插入一個(gè)文檔,該文檔包含 name:”admin” birth:”1990-05-01T13:30:00Z”
查詢 dev 集合中數(shù)據(jù),顯示 birth 字段的各部分?jǐn)?shù)據(jù),包括:年、月、日等信息。
顯示年月日
db.dev.aggregate([{$match:{name:“admin”}},{$project:{ 年份 :{$year:“$birth”}, 月 份:{$month:“$birth”},日:{$dayOfMonth:“$birth”}}}])
{$year:“$birth”}年份
{$month:“$birth”}月份
{$dayOfMonth:“$birth”}日期
顯示小時(shí)、分鐘、秒、毫秒
db.dev.aggregate([{$match:{name:“admin”}},{$project:{ 年 份 :{$year:“$birth”}, 月 份 :{$month:“$birth”}, 日 :{$dayOfMonth:“$birth”}, 時(shí) :{$hour:“$birth”}, 分 :{$minute:“$birth”}, 秒:{$second:“$birth”},毫秒:{$millisecond:“$birth”}}}])
{$hour:“$birth”}:小時(shí)
{$minute:“$birth”}:分鐘
{$second:“$birth”}:秒
{$millisecond:“$birth”}:毫秒
顯示星期、全年的第幾周、全年中的第幾天
db.dev.aggregate([{$match:{name:“admin”}},{$project:{ 年 份 :{$year:“$birth”}, 月 份 :{$month:“$birth”}, 日 :{$dayOfMonth:“$birth”}, 時(shí) :{$hour:“$birth”}, 分 :{$minute:“$birth”}, 秒:{$second:“$birth”},毫秒:{$millisecond:“$birth”},星期:{$dayOfWeek:“$birth”},全年的第幾 周:{$week:“$birth”},全年中的第幾天:{$dayOfYear:“$birth”}}}])
{$dayOfWeek:“$birth”}:星期日為 1,星期六為 7。
{$week:“$birth”}:全年的周計(jì)數(shù)從 0 開始。
{$dayOfYear:“$birth”}:全年中的第幾天。
顯示自定義日期格式
db.dev.aggregate([{$match:{name:“admin”}},{$project:{ 年 份 :{$year:“$birth”}, 月 份 :{$month:“$birth”}, 日 :{$dayOfMonth:“$birth”}, 時(shí) :{$hour:“$birth”}, 分 :{$minute:“$birth”}, 秒:{$second:“$birth”},毫秒:{$millisecond:“$birth”},星期:{$dayOfWeek:“$birth”},全年的第幾 周 :{$week:“$birth”}, 全 年 中 的 第 幾 天 :{$dayOfYear:“$birth”}, 自 定 義 日 期 格式:{$dateToString:{format:“%Y 年%m 月%d 日 %H:%M:%S”,date:“$birth”}}}}])
{$dateToString:{format:“%Y 年%m月%d 日 %H:%M:%S”,date:“$birth”}
自定義日期格式 具體格式如下:
九、 Java 訪問 MongoDB
1 連接 MongoDB 數(shù)據(jù)庫
1.1創(chuàng)建工程
在 POM 文件中添加 MongoDB 驅(qū)動(dòng)坐標(biāo)
<!--添加 MongoDB 驅(qū)動(dòng)坐標(biāo)--><dependency><groupId>org.mongodb</groupId><artifactId>mongo-java-driver</artifactId><version>3.8.2</version></dependency>
1.2創(chuàng)建 MongoDB 連接
封裝 MongoDBUtil
package utils;import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;/*** 封裝 MongoDBUtil*/
public class MongoDBUtil {private static MongoClient client = null;static {if (client == null) {client = new MongoClient("192.168.66.100", 27017);}}//獲取 MongoDB 數(shù)據(jù)庫public static MongoDatabase getDatabase(String dbName) {return client.getDatabase(dbName);}//獲取 MongoDB 中的集合public static MongoCollection getCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);return database.getCollection(collName);}}
1.3創(chuàng)建 MongoDB 的認(rèn)證連接
封裝 MongoDBAuthUtil
package utils;import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;import java.util.Arrays;/*** 封裝 MongoDBUtil-使用用戶認(rèn)證*/
public class MongoDBAuthUtil {private static MongoClient client = null;static {if (client == null) {//創(chuàng)建一個(gè)封裝用戶認(rèn)證信息MongoCredential credential = MongoCredential.createCredential("itsxt", "develop", "itsxt pwd".toCharArray());//封裝 MongoDB 的地址與端口ServerAddress address = newServerAddress("192.168.66.100", 27017);client = new MongoClient(address, Arrays.asList(credential));}}//獲取 MongoDB 數(shù)據(jù)庫public static MongoDatabase getDatabase(String dbName) {return client.getDatabase(dbName);}//獲取 MongoDB 中的集合public static MongoCollection getCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);return database.getCollection(collName);}}
1.4創(chuàng)建 MongoDB 的池連
封裝 MongoDBPoolUtil
package utils;import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;/*** 使用池連的方式獲取連接*/
public class MongoDBPoolUtil {private static MongoClient client = null;static {if (client == null) {MongoClientOptions.Builder builder = new MongoClientOptions.Builder();builder.connectionsPerHost(10);//每個(gè)地址的最大連接數(shù)builder.connectTimeout(5000);//連接超時(shí)時(shí)間builder.socketTimeout(5000);//設(shè)置讀寫操作超時(shí)時(shí)間ServerAddress address = new ServerAddress("192.168.66.100", 27017);client = new MongoClient(address, builder.build());}}//獲取 MongoDB 數(shù)據(jù)庫public static MongoDatabase getDatabase(String dbName) {return client.getDatabase(dbName);}//獲取 MongoDB 中的集合public static MongoCollection getCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);return database.getCollection(collName);}
}
1.5創(chuàng)建 MongoDB 的認(rèn)證池連
封裝 MongoDBAuthPoolUtil
package utils;import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;/*** 支持用戶認(rèn)證的池連*/
public class MongoDBAuthPoolUtil {private static MongoClient client = null;static {if (client == null) {MongoClientOptions.Builder builder = new MongoClientOptions.Builder();builder.connectionsPerHost(10);//每個(gè)地址的最大連接數(shù)builder.connectTimeout(5000);//連接超時(shí)時(shí)間builder.socketTimeout(5000);//設(shè)置讀寫操作超時(shí)時(shí)間//創(chuàng)建一個(gè)封裝用戶認(rèn)證信息MongoCredential credential =MongoCredential.createCredential("itsxt", "develop", "itsxtpwd".toCharArray());//封裝 MongoDB 的地址與端口hServerAddress address = new ServerAddress("192.168.66.100", 27017);client = new MongoClient(address, credential, builder.build());}}//獲取 MongoDB 數(shù)據(jù)庫public static MongoDatabase getDatabase(String dbName) {return client.getDatabase(dbName);}//獲取 MongoDB 中的集合public static MongoCollection getCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);return database.getCollection(collName);}//創(chuàng)建集合public static void createCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);database.createCollection(collName);}//刪除集合public static void dropCollection(MongoCollection coll) {coll.drop();}}
2 操作集合
2.1創(chuàng)建集合
//創(chuàng)建集合public static void createCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);database.createCollection(collName);}
2.2獲取集合
//獲取 MongoDB 中的集合public static MongoCollection getCollection(String dbName, String collName) {MongoDatabase database = getDatabase(dbName);return database.getCollection(collName);}
2.3刪除集合
//刪除集合public static void dropCollection(MongoCollection coll) {coll.drop();}
3 操作文檔
3.1添加文檔
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import utils.MongoDBAuthPoolUtil;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class AddDocument {public static void main(String[] args) {new AddDocument().insertSingleDocument();}/*** 添加單個(gè)文檔*/public void insertSingleDocument() {MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop", "devtest");// {}---->Document//append(String key,Object value)---->{key:value}Document docu = new Document();docu.append("username", "lisi").append("userage", 26).append("userdesc", "Very Good").append("userlike", Arrays.asList(new String[]{"Music", "Sport"}));collection.insertOne(docu);}/*** 文檔的批量添加*/public void insertManyDocument() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");List<Document> list = new ArrayList<>();for (int i = 0; i < 5; i++) {Document docu = new Document();docu.append("username", "zhangsan" + i);docu.append("userage", 20 + i);docu.append("userdesc", "OK" + i);docu.append("userlike", Arrays.asList(newString[]{"Music", "Sport"}));list.add(docu);}collection.insertMany(list);}
}
3.2更新文檔
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import utils.MongoDBAuthPoolUtil;public class UpdateDocument {public static void main(String[] args) {new UpdateDocument().updateDocumentArray();}/*** 更新單個(gè)文檔單個(gè)鍵*/public void updateSingleDocumentSingleKey() {MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop", "devtest");//更新文檔//Filters 封裝了條件的一個(gè)工具類{$set:{userage:28}}collection.updateOne(Filters.eq("username", "lisi"),new Document("$set", new Document("userage", 28)));}/*** 更新單個(gè)文檔多個(gè)鍵*/public void updateSingleDocumentManyKey() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");collection.updateOne(Filters.eq("username", "zhangsan0"),new Document("$set", new Document("userage", 18).append("userdesc", "Very Good")));}/*** 更新多個(gè)文檔單個(gè)鍵*/public void updateManyDocumentSingleKey() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");collection.updateMany(Filters.ne("username", null), newDocument("$set", new Document("userdesc", "Very Good")));}/*** 更新多個(gè)文檔多個(gè)鍵*/public void updateManyDocumentManyKey() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");collection.updateMany(Filters.ne("username", null), newDocument("$set", new Document("userdesc", "OK").append("userage", 20)));}/*** 更新文檔中的數(shù)組* {$push:{}}*/public void updateDocumentArray() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");collection.updateOne(Filters.eq("username", "lisi"),new Document("$push", new Document("userlike", "Art")));}}
3.3查詢文檔
查詢?nèi)课臋n
/*** 查詢?nèi)课臋n*/public void selectDocumentAll() {MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop", "devtest");//返回的是一個(gè)文檔的迭代器FindIterable<Document> iterable = collection.find();MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("_id") + "\t" + docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
根據(jù)_id 查詢文檔-$eq
/*** 根據(jù)_id 查詢文檔*/public void selectDocumentById() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable<Document> iterable =collection.find(Filters.eq("_id", new ObjectId("642aa799b1058b2c108fc447")));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢多個(gè)文檔-$gt
/*** 根據(jù)年齡查詢文檔,條件是年齡大于 19*/public void selectDocumentConditionByGt() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.gt("userage", 19));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢多個(gè)文檔-$type
/*** 根據(jù)年齡查詢文檔,添加是年齡的值是整數(shù)類型(number)*/public void selectDocumentConditionByType() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.type("userage", "number"));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢多個(gè)文檔-$in
/*** 查詢用戶的名字為 zhangsan1,zhangsan2*/public void selectDocumentConditionByIn() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.in("username", "zhangsan1", "zhangsan2"));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢多個(gè)文檔-$nin
/*** 查詢用戶的名字不是 zhangsan1,zhangsan2*/public void selectDocumentConditionByNin() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.nin("username", "zhangsan1", "zhangsan2"));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢多個(gè)文檔-$regex
/*** 查詢用戶的名字是 z 開頭 2 結(jié)尾的。*/public void selectDocumentConditionByRegex() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.regex("username",Pattern.compile("^z.*2$")));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
邏輯運(yùn)算符-$and
/*** 查詢用戶 username 是 zhangsan1 并且年齡為 20 歲的用戶*/public void selectDocumentConditionUseAnd() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.and(Filters.eq("username", "zhangsan1"),Filters.eq("userage", 20)));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
邏輯運(yùn)算符-$or
/*** 查詢用戶要求 username 是 lisi,或者 userage 是 20 或者 userdesc是 Very Good*/public void selectDocumentConditionUseOr() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.or(Filters.eq("username", "lisi"),Filters.eq("userage", 20),Filters.eq("userdesc", "Very Good")));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
邏輯運(yùn)算符-$and 與$or 聯(lián)合使用
/*** /*** * 查詢文檔中 username 為 lisi 并且年齡為 20 歲,或者 userdesc 為 Very Good*/public void selectDocumentConditionAndOr() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.or(Filters.and(Filters.eq("username", "lisi"),Filters.eq("userage", 20)),Filters.eq("userdesc", "Very Good")));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
查詢文檔-排序處理
/*** 查詢文檔中 username 是 z 開頭的,根據(jù) username 對結(jié)果做降序排序。1* 升序排序, -1 降序排序規(guī)則 $sort:{username,-1}*/public void selectDocumentSorting() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");FindIterable iterable =collection.find(Filters.regex("username", Pattern.compile("^z"))).sort(new Document("username", -1));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike"));}}
3.4日期操作
插入系統(tǒng)當(dāng)前日期
/*** 插入系統(tǒng)當(dāng)前日期*/public void insertDocumentSystemDate() {MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop", "devtest");Document docu = new Document();docu.put("username", "wangwu");docu.put("userage", 22);docu.put("userdesc", "Very Good");docu.put("userlike", Arrays.asList(newString[]{"Music", "Art"}));docu.put("userbirth", new Date());collection.insertOne(docu);}
插入指定日期
創(chuàng)建日期處理工具類
package utils;import java.text.SimpleDateFormat;
import java.util.Date;public class DateUtil {/*** Date To String*/public static String dateToString(String pattern, Date date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);return simpleDateFormat.format(date);}/*** String To Date*/public static Date stringToDate(String pattern, String date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);Date d = null;try {d = simpleDateFormat.parse(date);} catch (Exception e) {e.printStackTrace();}return d;}
}
添加指定日期
/*** 插入指定日期*/public void insertDocumentCursorDate() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");Date date = DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss", "2019-05-01 13:32:13");Document docu = new Document();docu.put("username", "zhaoliu");docu.put("userage", 24);docu.put("userdesc", "Very Good");docu.put("userlike", Arrays.asList(new String[]{"Music", "Art"}));docu.put("userbirth", date);collection.insertOne(docu);}
查詢?nèi)掌?$eq
/*** 查詢用的生日為 2019-05-01 13:32:13 的用戶信息*/public void selectDocumentDateUseEq() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");Date date = DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss", "2019-05-01 13:32:13");FindIterable iterable =collection.find(Filters.eq("userbirth", date));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();String temp = DateUtil.dateToString("yyyy-MM-dd HH:mm:ss", (Date) docu.get("userbirth"));System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike") + "\t" + temp);}}
查詢?nèi)掌?$gt
/*** 查詢?nèi)掌?#xff1a;查詢用的生日大于 2019-01-01 00:00:00 的用戶信息*/public void selectDocumentDateUseGt() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");Date date = DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss", "2019-01-01 00:00:00");FindIterable iterable =collection.find(Filters.gt("userbirth", date));MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();String temp = DateUtil.dateToString("yyyy-MM-dd HH:mm:ss", (Date) docu.get("userbirth"));System.out.println(docu.get("username") + "\t" + docu.get("userage") + "\t"+ docu.get("userdesc") + "\t" + docu.get("userlike") + "\t" + temp);}}
3.5聚合操作
聚合操作-計(jì)算文檔總數(shù)-$sum
需求:查詢集合中的文檔數(shù)量
Mongo Shell:db.dev.aggregate([{$group:{_id:null,count:{$sum:1}}}])
/*** 需求:查詢集合中的文檔數(shù)量* Mongo Shell:db.dev.aggregate([{$group:{_id:null,count:{$sum:1}}}])*/public void selectDocumentAggregateCount() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document sum = new Document();sum.put("$sum", 1);Document count = new Document();count.put("_id", null);count.put("count", sum);Document group = new Document();group.put("$group", count);List<Document> list = new ArrayList<>();list.add(group);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("count"));}}
聚合操作-計(jì)算值的總和-$sum
需求:查詢集合中所有 size 鍵中的值的總和
Mongo Shell:db.dev.aggregate([{$group:{_id:null,totalSize:{$sum:“$size”}}}])
/*** 需求:查詢集合中所有 size 鍵中的值的總和* Mongo Shell:db.dev.aggregate([{$group:{_id:null,totalSize:{$sum:"$size"}}}])*/public void selectDocumentAggregateSum() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document sum = new Document();sum.put("$sum", "$size");Document totalSize = new Document();totalSize.put("_id", null);totalSize.put("totalSize", sum);Document group = new Document();group.put("$group", totalSize);List<Document> list = new ArrayList<>();list.add(group);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("totalSize"));}}
聚合操作-在分組中計(jì)算值的總和-$sum
需求:對 title 進(jìn)行分組,計(jì)算每組中的 size 的總和
Mongo Shell:db.dev.aggregate([{$group:{_id:“$title”,totalSize:{$sum:“$size”}}}])
/*** 需求:對 title 進(jìn)行分組,計(jì)算每組中的 size 的總和* Mongo Shell:db.dev.aggregate([{$group:{_id:"$title",totalSize:{$sum:"$size"}}}])*/public void selectDocumentAggregateGroupBySum() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document sum = new Document();sum.put("$sum", "$size");Document totalSize = new Document();totalSize.put("_id", "$title");totalSize.put("totalSize", sum);Document group = new Document();group.put("$group", totalSize);List<Document> list = new ArrayList<>();list.add(group);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("totalSize"));}}
聚合操作-分組前的數(shù)據(jù)過濾-$match
需求:查詢 dev 集合有多少文檔的 size 大于 200。
Mongo Shell:
db.dev.aggregate([{$match:{size:{$gt:200}}},{$group:{_id:null,totalSize:{$sum:1}}}])
/* 需求:查詢 dev 集合有多少文檔的 size 大于 200。Mongo Shell:db.dev.aggregate([{$match:{size:{$gt:200}}},{$group:{_id:null,totalSize:{$sum:1}}}])*/public void selectDocumentAggregateGroupByWhere() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document gt = new Document();gt.put("$gt", 200);Document size = new Document();size.put("size", gt);Document match = new Document();match.put("$match", size);Document sum = new Document();sum.put("$sum", 1);Document totalSize = new Document();totalSize.put("_id", null);totalSize.put("totalSize", sum);Document group = new Document();group.put("$group", totalSize);List<Document> list = new ArrayList<>();list.add(match);list.add(group);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("totalSize"));}}
聚合操作-分組后的數(shù)據(jù)過濾-$match
需求:查詢 dev 集合,根據(jù) title 分組計(jì)算出每組的 size 的總和,并過濾掉總和小于 200 的文檔。
Mongo Shell:
db.dev.aggregate([{$group:{_id:“$title”,totalSize:{$sum:“$size”}}},{$match:{totalSize:{$gt: 200}}}])
/*** 需求:查詢 dev 集合,根據(jù) title 分組計(jì)算出每組的 size 的總和,并過* 濾掉總和小于 200 的文檔。* Mongo Shell:* db.dev.aggregate([{$group:{_id:"$title",totalSize:{$sum:"$size"}}},* {$match:{totalSize:{$gt:200}}}])*/public void selectDocumentAggregateGroupByHaving() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");//{$group:{_id:"$title",totalSize:{$sum:"$size"}}}Document sum = new Document();sum.put("$sum", "$size");Document totalSize = new Document();totalSize.put("_id", "$title");totalSize.put("totalSize", sum);Document group = new Document();group.put("$group", totalSize);//{$match:{totalSize:{$gt:200}}}Document gt = new Document();gt.put("$gt", 200);Document mtotalSize = new Document();mtotalSize.put("totalSize", gt);Document match = new Document();match.put("$match", mtotalSize);List<Document> list = new ArrayList<>();list.add(group);list.add(match);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu.get("totalSize"));}}
聚合操作-$project-聚合投影約束
需求:查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示,并只顯示 title 鍵與 tags 鍵的值。
Mongo Shell:
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,tags:“$tags”,title:“$title”}}])
/*** 需求:查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示,并只顯示 title 鍵與 tags* 鍵的值。* Mongo Shell:* db.dev.aggregate([{$unwind:"$tags"},* {$project:{_id:0,tags:"$tags",title:"$title"}}])*/public void selectDocumentProject() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document unwind = new Document();unwind.put("$unwind", "$tags");Document pro = new Document();pro.put("_id", 0);pro.put("tags", "$tags");pro.put("title", "$title");Document project = new Document();project.put("$project", pro);List<Document> list = new ArrayList<>();list.add(unwind);list.add(project);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {System.out.println(cursor.next());}}
聚合操作-$project-字符串處理
需求:查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。將 title 字段和 tags 字段的值拼接為 一個(gè)完整字符串并在 Title_Tags 字段中顯示。
Mongo Shell:
db.dev.aggregate([{$unwind:“$tags”},{$project:{_id:0,Title_Tags:{$concat:[“$title”,“-”,“$tag s”]}}}])
/*** 需求:查詢 dev 集合,將數(shù)組中的內(nèi)容拆分顯示。將 title 字段和 tags* 字段的值拼接為一個(gè)完整字符串并在 Title_Tags 字段中顯示。* Mongo Shell:* db.dev.aggregate([{$unwind:"$tags"},* {$project:{_id:0,Title_Tags:{$concat:["$title","-","$tags"]}}}])*/public void selectDocumentProjectConcat() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document unwind = new Document();unwind.put("$unwind", "$tags");Document concat = new Document();concat.put("$concat", Arrays.asList(new String[]{"$title", "-", "$tags"}));Document title = new Document();title.put("_id", 0);title.put("Title_Tags", concat);Document project = new Document();project.put("$project", title);List<Document> list = new ArrayList<>();list.add(unwind);list.add(project);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {System.out.println(cursor.next());}}
聚合操作-$project 算術(shù)運(yùn)算
需求:查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)據(jù)做加 1 操作,顯 示字段命名為 New_Size。排除那些沒有 size 鍵的文檔。
Mongo Shell:
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$add:[“$size”,1]}}}])
/*** 需求:查詢 dev 集合中數(shù)據(jù),顯示 title 和 size 字段,為 size 字段數(shù)* 據(jù)做加 1 操作,顯示字段命名為 New_Size。排除那些沒有 size 鍵的文檔。* Mongo Shell:* db.dev.aggregate([* {$match:{size:{$ne:null}}},* {$project:{_id:0,title:1,New_Size:{$add:["$size",1]}}}])*/public void selectDocumentProjectAdd() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");//{$match:{size:{$ne:null}}}Document ne = new Document();ne.put("$ne", null);Document size = new Document();size.put("size", ne);Document match = new Document();match.put("$match", size);//{$project:{_id:0,title:1,New_Size:{$add:["$size",1]}}}Document add = new Document();add.put("$add", Arrays.asList(new Object[]{"$size", 1}));Document new_Size = new Document();new_Size.put("_id", 0);new_Size.put("title", 1);new_Size.put("New_Size", add);Document project = new Document();project.put("$project", new_Size);List<Document> list = new ArrayList<>();list.add(match);list.add(project);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {System.out.println(cursor.next());}}
聚合操作-$project 日期處理
需求:查詢 devtest 集合查詢那些有生日的用戶,并按照 YYYY 年 mm 月 dd 日 HH:MM:SS 格式顯示日期。
Mongo Shell:
db.devtest.aggregate([{$match:{userbirth:{$ne:null}}},{$project:{ 自定義日期格 式:{$dateToString:{format:“%Y 年%m 月%d 日 %H:%M:%S”,date:“$userbirth”}}}}])
/*** 需求:查詢 devtest 集合查詢那些有生日的用戶,并按照 YYYY 年 mm 月dd 日 HH:MM:SS 格式顯示日期。* 注意:如果直接在 MongoDB 中做日期的格式化處理,那么是按照表示 UTC時(shí)間來處理的,會(huì)少 8個(gè)小時(shí)。* 建議在程序中通過 java.util.Date 來做日期的轉(zhuǎn)換。* Mongo Shell:* db.devtest.aggregate([* {$match:{userbirth:{$ne:null}}},* {$project:{自定義日期格式:{$dateToString:{format:"%Y 年%m 月%d 日 %H:%M:%S",date:"$userbirth"}}}}])*/public void selectDocumentProjectDate() {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "devtest");//{$match:{userbirth:{$ne:null}}}Document ne = new Document();ne.put("$ne", null);Document birth = new Document();birth.put("userbirth", ne);Document match = new Document();match.put("$match", birth);//{$project:{自定義日期格式:{$dateToString:{format:"%Y年%m 月%d 日 %H:%M:%S",date:"$userbirth"}}}}Document format = new Document();format.put("format", "%Y 年%m 月%d 日 %H:%M:%S");format.put("date", "$userbirth");Document dateToString = new Document();dateToString.put("$dateToString", format);Document custoDate = new Document();custoDate.put("自定義日期格式", dateToString);Document project = new Document();project.put("$project", custoDate);List<Document> list = new ArrayList<>();list.add(match);list.add(project);AggregateIterable iterable = collection.aggregate(list);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {System.out.println(cursor.next());}}
3.6分頁查詢
使用 skip 與 limit 方法分頁
/*** 通過 skip 與 limit 方法實(shí)現(xiàn)分頁*/public void selectDocumentByPageUseSkipAndLimit(int pageIndex) {int page = (pageIndex - 1) * 2;MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document condition = new Document("size", new Document("$ne", null));long countNum = collection.countDocuments(condition);System.out.println(countNum);FindIterable iterable = collection.find(condition).skip(page).limit(2);MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu);}}
優(yōu)化分頁查詢
使用條件判斷替換 skip 方法
/*** 通過條件判斷實(shí)現(xiàn)分頁*/public void selectDocumentByPageUseCondition(int pageIndex, int pageSize, String lastId) {MongoCollection collection =MongoDBAuthPoolUtil.getCollection("develop", "dev");Document condition = new Document("size", new Document("$ne", null));long countNum = collection.countDocuments(condition);System.out.println(countNum);FindIterable iterable = null;if (pageIndex == 1) {iterable = collection.find(condition).limit(pageSize);} else {if (lastId != null) {condition.append("_id", new Document("$gt", new ObjectId(lastId)));iterable = collection.find(condition).limit(pageSize);}}MongoCursor<Document> cursor = iterable.iterator();while (cursor.hasNext()) {Document docu = cursor.next();System.out.println(docu);}}