MongoDB一篇從入門到實戰
MongoDB資料庫介紹
1、MongoDB簡介
MongoDB官網:https://www.mongodb.com
- MongoDB 是由C++語言編寫的,是一個基於分散式檔案儲存的開源資料庫系統。
- MongoDB 可在高負載的情況下,新增更多的節點,可以保證伺服器效能。
- MongoDB 可為Web應用提供可擴充套件的高效能資料儲存解決方案。
- MongoDB 將資料儲存在靈活的json文件中,這意味著可以直接得到從文件到文件的資料、結構等。
- MongoDB 是免費使用的(MongoDB分 社群版 [在所有環境下都免費] 和 企業版[在開發環境免費,生產環境收費] 兩個版本)。
- MongoDB 資料庫具有可伸縮性和靈活性,可幫助你快速查詢和索引你需要資料。
MongoDB 是一個介於關聯式資料庫和非關聯式資料庫之間的產品,是非關聯式資料庫當中功能最豐富,最像關聯式資料庫的。
它是可擴充套件的高效能資料儲存解決方案,經常被用於非關係型資料的儲存,能儲存海量的資料。
常見的非關係型資料庫還有:Redis,但 MongoDb 比 redis 更具有資料庫的特性。
-
關係型資料庫有:MySQL、Oracle、SQL Serve…
-
非關係型資料庫有:Redis、MongoDB…
對比
傳統的關係型資料庫(如 MySQL)儲存資料使用的是一種“行/列模型”。而 MongoDB 是一種“文件資料庫”,它將資料儲存在類似 JSON 的文件中。
以 JSON 文件的方式儲存資料,其中的好處有很多。比如,支援使用陣列和物件作為值、文件間可以巢狀、查詢的本身就是一個 JSON 等。
2、基本資料結構
與 MySQL 等關係型資料庫一樣,MongoDb 也有類似的概念,但是其稱呼不同。下表列出了 MongoDb 的基本資料結構以及與 MySQL 的對比。
SQL術語/概念 | MongoDB術語/概念 | 解釋/說明 |
---|---|---|
database | database | 資料庫 |
table | collection | 資料庫表/集合 |
row | document | 資料記錄行/文件 |
column | field | 資料欄位/域 |
index | index | 索引 |
table joins | 表連線,MongoDb不支援 | |
primary key | primary key | 主鍵,MongoDb自動將_id欄位設定為主鍵 |
3、基本資料型別
資料型別 | 描述 |
---|---|
String | 字串。儲存資料常用的資料型別。在 MongoDB 中,UTF-8 編碼的字串才是合法的。 |
Integer | 整型數值。用於儲存數值。根據你所採用的伺服器,可分為 32 位或 64 位。 |
Boolean | 布林值。用於儲存布林值(真/假)。 |
Double | 雙精度浮點值。用於儲存浮點值。 |
Min/Max keys | 將一個值與 BSON(二進位制的 JSON)元素的最低值和最高值相對比。 |
Array | 用於將陣列或列表或多個值儲存為一個鍵。 |
Object | 用於內嵌文件。 |
Null | 用於建立空值。 |
Symbol | 符號。該資料型別基本上等同於字串型別,但不同的是,它一般用於採用特殊符號型別的語言。 |
Date | 日期時間。用 UNIX 時間格式來儲存當前日期或時間。你可以指定自己的日期時間:建立 Date 物件,傳入年月日資訊。 |
Object ID | 物件 ID。用於建立文件的 ID。(如果不指定的話,mongodb預設會給一個 _id) |
Binary Data | 二進位制資料。用於儲存二進位制資料。 |
Code | 程式碼型別。用於在文件中儲存 JavaScript 程式碼。 |
Regular expression | 正規表示式 |
MongoDB下載與安裝
1、Win10安裝
官網下載 地址:https://www.mongodb.com/try/download/community
其他下載方式:除了上面的下載方式以外,也可以試試下面的下載連結!
**MongoDB Windows系統64位下載地址:**http://www.mongodb.org/dl/win32/x86_64
**MongoDB Windows系統32位下載地址:**http://www.mongodb.org/dl/win32/i386
**MongoDB 全部版本下載地址:**http://www.mongodb.org/dl/win32
1、下載指定版本
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Rp5UQyqx-1609051910724)(MongoDB快速入門/20201210220729.png)]
- MongoDB Enterprise Server:企業版(收費版)
- MongoDB Community Server:社群版(免費版)(我們下載社群版本)
- 下載完成後,獲得安裝包:
mongodb-windows-x86_64-4.4.2-signed.msi
,雙擊即可安裝。
2、選擇安裝方式:
- 如果已經安裝過該版本的MongoDB,會是這個介面(如果沒有安裝過忽略此步驟)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-KKCAGH0g-1609051910726)(MongoDB快速入門/20201211231045.png)]
-
選擇Complete,表示安裝到預設路徑(不推薦,C盤懂的都懂)
-
選擇Custom,表示自定義安裝路徑(推薦)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-0bZXSFSl-1609051910728)(MongoDB快速入門/20201211231046.png)]
3、選擇安裝路徑:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-lDuJGVkq-1609051910730)(MongoDB快速入門/20201211231456.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-oUkoTNvQ-1609051910732)(MongoDB快速入門/20201211232513.png)]
注意:MongoDB 3.x 系列版本的資料庫,在安裝成功後,每次在使用前都需要手動啟動MongoDB服務!
現在:MongoDB 4.x 系列版本的資料庫,在安裝時預設安裝(選中了 Install MongoD as a Service)服務 ,就是在開機時自動啟動 MongoDB 服務,然後就可以直接使用啦!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ZdVjpNIT-1609051910733)(MongoDB快速入門/20201211233227.png)]
4、然後就一直下一步、Next 直到 Flnish 安裝完畢,到此就MongoDB就安裝結束啦!
5、檢查是否安裝成功(Windows環境下)
- 方式一:
1、執行 Win + R
2、輸入 services.msc 命令便可以檢視到 MongoDB Server (MongoDB) 服務啦!!
- 方式二:
1、開啟任意瀏覽器輸入:http://127.0.0.1:27017/
2、返回如下資訊代表安裝成功:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
- 方式三:
C:\Users\lenovo>mongod -version
db version v4.4.2
Build Info: {
"version": "4.4.2",
"gitVersion": "15e73dc5738d2278b688f8929aee605fe4279b0e",
"modules": [],
"allocator": "tcmalloc",
"environment": {
"distmod": "windows",
"distarch": "x86_64",
"target_arch": "x86_64"
}
}
6、目錄檔案說明:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-OjCCYJGp-1609051910733)(MongoDB快速入門/20201212120352.png)]
預設配置檔案:bin/mongod.cfg
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: D:\Environment\MongoDB\Server\4.4\data # 資料儲存目錄
journal:
enabled: true
# where to write logging data.
systemLog:
destination: file
logAppend: true # 日誌採用追加模式
path: D:\Environment\MongoDB\Server\4.4\log\mongod.log # 日誌檔案地址
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1 # 資料庫埠號
# 開啟資料庫訪問許可權驗證(注意:換行、縮排格式哦!!)
security:
authorization: enabled
7、配置環境變數(選配,看個人喜好,為了使用方便我配置了)
配置完畢後就是在電腦中任何地方都可以合用mongo、mongod等命令
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-R4Wkxgtq-1609051910734)(MongoDB快速入門/20201212110639.png)]
8、mongod.exe 和 mongo.exe 命令
一定要以管理員身份啟動CMD!一定要以管理員身份啟動CMD!一定要以管理員身份啟動CMD!
這兩個命令的作用分別是:
- mongod 啟動 MongoDB 伺服器。
- mongo 在啟動伺服器後,幫助我們連線到 MongoDB 例項,也就是進入 Mongo shell(相當於讓我們進入後臺運算元據庫)。
mongod
命令啟動引數:
引數 | 描述 |
---|---|
–config或-f | 指定配置檔案路徑 |
–bind_ip | 繫結服務IP,若繫結127.0.0.1,則只能本機訪問,不指定預設本地所有IP(0.0.0.0) |
–dbpath | 指定資料庫路徑 |
–logpath | 定MongoDB日誌檔案,注意是指定檔案不是目錄 |
–logappend | 使用追加的方式寫日誌 |
–port | 指定服務埠號,預設埠27017 |
–serviceName | 指定服務名稱 |
–serviceDisplayName | 指定服務名稱,有多個mongodb服務時執行。 |
–install | 指定作為一個Windows服務安裝。 |
–remove | 移除MongoDB服務 |
–auth | 表示載入認證功能 |
mongod
命令安裝示例:
######################## MongoDB方式建立win服務:########################
# 安裝 MongoDB 服務,指定配置檔案安裝(沒有指定服務名的話預設服務名為:MongoDB)
mongod --config "D:\Environment\MongoDB\Server\4.4\bin\mongod.cfg" --install
# 或者
mongod --bind_ip 0.0.0.0 --dbpath "D:\Environment\MongoDB\Server\4.4\data\db" --logpath "D:\Environment\MongoDB\Server\4.4\log\mongod.log" --logappend --port 27017 --serviceName "MongoDB" --serviceDisplayName "MongoDB" --install
# 啟動和關閉 MongoDB 服務,該名稱位--serviceName設定的名稱
net start MongoDB
net stop MongoDB
# 移除 MongoDB 服務,必須先關閉 MongoDB 服務
mongod --remove
######################## windows自帶建立win服務方式:########################
# 建立 MongoDB 服務(中間幾個引號很關鍵)
sc.exe create MongoDB binPath= "\"D:\Environment\MongoDB\bin\mongod.exe\" --service --config= \"E:\Environment\MongoDB\mongo.config"" DisplayName= "MongoDB" start= "auto"
# 刪除 MongoDB 服務
sc delete MongoDB
mongo
命令:進入 MongoDB Shell介面(登入)
# 1、mongo # 直接進入
# 2、mongo 127.0.0.1:27017/config # 連線到任何資料庫config
# 3、mongo --nodb #不連線到任何資料庫
# 4、啟動之後,在需要時執行new Mongo(hostname)命令就可以連線到想要的mongod了:
> conn=new Mongo('127.0.0.1:27017')
connection to 127.0.0.1:27017
> db=conn.getDB('admin')
admin
# 4、help檢視幫助
# mongo -u admin -p password # 連線本地資料庫,使用了--auth啟動,輸入賬號密碼
# 連線運程MongoDB資料庫:(必須指定 繫結IP 和 埠號)
# 格式:mongo 繫結IP:埠號/資料庫名 -u 使用者名稱 -p 密碼
mongo 127.0.0.1:27017/test -u admin -p password
或者
mongo --host 127.0.0.1 --port 27017
# 也可以登入shell後輸入使用者名稱和密碼登入
db.auth("admin", "password")
2、Linux安裝
MongoDB官網下載地址:https://www.mongodb.com/try/download/community
1、安裝步驟:
# 1.切換opt目錄
$ cd /opt/
# 2.wget下載安裝包
$ wget -P /opt/ https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-4.4.2.tgz
# 3.解壓
$ tar -xzvf /opt/mongodb-linux-x86_64-amazon-4.4.2.tgz
# 4.移動目錄並且重新命名
$ mv /opt/mongodb-linux-x86_64-amazon-4.4.2 /usr/local/mongodb
# 5.新建data和logs目錄
$ mkdir -p /usr/local/mongodb/{data,logs}
# 6.授權目錄
$ chmod 777 /usr/local/mongodb/{data,logs}
# 7.profile配置檔案中增加環境變數,然後重新整理配置
$ echo "export PATH=\$PATH:/usr/local/mongodb/bin" >> /etc/profile && source /etc/profile
2、啟動MongoDB服務
MongoDB 的啟動方式分為兩種:前置啟動、後置啟動
無論哪種啟動方式都需要執行 bin 目錄中的 mongod 命令。MongoDB 在啟動時預設的查詢資料庫的路徑為/data/db。如果我們資料庫路徑有變化,需要在該命令中通過–dbpath 參數來指定 db 目錄的路徑(該路徑可以是絕對路徑,也可是相對路徑)
2.1、前置啟動(配置引數)
# data 目錄需要提前建立
mongod --dbpath /usr/local/mongodb/data
2.2、後置啟動(配置引數)
所謂後置啟動就是以守護程式的方式啟動 MongoDB。
我們需要在執行 mongod 命令中新增 --fork 引數。需要注意的是,–fork 引數需要配合著–logpath 或者是–syslog 引數使用。–logpath 與–syslog 引數是指定 MongoDB 的日誌檔案。MongoDB 的日誌檔案可以在系統中*的任意位置,本文章中我們在 mongodb 目錄下建立 log 目錄,在該目錄中建立一個名為mongodb.log 的日誌檔案。
# data和logs目錄需要提交建立,mongodb.log檔案可不建立。--fork後臺啟動
mongod --dbpath /usr/local/mongodb/data --logpath /usr/local/mongodb/logs/mongodb.log --fork
2.3、配置檔案方式啟動
如果覺得在啟動 MongoDB 時給定的引數項太多,那麼我們也可以通過配置檔案來配置啟動引數,配置檔案可以在任意目錄中,配置檔案的副檔名應為.conf,配置檔案中使用key=value 結構。在執行 MongoDB 時通過–config 引數來指定需要載入的配置檔案。我們在 /bin 目錄中建立一個名為 mongodb.conf 配置檔案
# 1.建立配置檔案 mongodb.conf
$ sudo tee /usr/local/mongodb/bin/mongodb.conf <<-'EOF'
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/logs/mongodb.log
port=27017
fork=true
bind_ip=0.0.0.0
#auth=true
EOF
# 1.或vim 編輯
$ vim /usr/local/mongodb/bin/mongodb.conf
# 增加如下配置
dbpath=/usr/local/mongodb/data # 指定 db 路徑
logpath=/usr/local/mongodb/logs/mongodb.log # 指定日誌檔案
logappend=true # 使用追加的方式寫日誌
port=27017 # 配置埠
fork=true # 配置後端啟動
bind_ip=0.0.0.0 # 設定所有ip都可以訪問
journal=true # 每次寫入會記錄一條操作日誌(通過journal可以重新構造出寫入的資料)。
directoryperdb=true
quiet=true
bind_ip_all=true
auth=true # 啟動驗證
#noauth=true # 不啟用驗證
# 2.通過載入配置檔案啟動MongoDB
$ mongod -f /usr/local/mongodb/bin/mongodb.conf
$ mongod --config /usr/local/mongodb/bin/mongodb.conf
3、關閉MongoDB
-
Ctrl+C關閉(安全關閉):前置啟動的話可以直接使用快捷鍵 Ctrl+C 就可以關閉 MongoDB
-
kill命令關閉(非安全關閉):kill -9 PID、kill -2 PID、kill -4 PID
-
MongoDB函式關閉(安全關閉,要在admin庫執行):
db.shutdownServer()
、db.runCommand("shutdown")
-
mongod 命令關閉(安全關閉):./mongod --shutdown --dbpath<資料庫路徑>
示例:
## 方式一
> use admin
switched to db admin
> db.shutdownServer()
server should be down...
>
## 方式二
$ mongod --shutdown --dbpath /usr/local/mongodb/data/db
3、Docker安裝
docker 安裝
# 1.下載MongoDB Docker映象
$ docker pull mongo:4.4.2
$ docker pull mongo:latest
# 2.啟動MongoDB服務
$ docker run -itd -p 27017:27017 --name mongodb mongo:latest
$ docker run -itd -p 27017:27017 --name mongodb \
-v /mydata/mongo/db:/data/db
mongo:latest
# 3.啟動MongoDB服務並設定賬號
$ docker run -itd -p 27017:27017 --name mongodb mongo:latest --auth
$ docker run -itd -p 27017:27017 --name mongodb \
-v /mydata/mongo/db:/data/db \
mongo:latest --auth
# 4.進入容器中的MongoDB客戶端
$ docker exec -it mongodb mongo
# 5.在admin資料庫中建立超級管理員賬號
> use admin
> db.createUser({
user: 'admin',
pwd: 'password',
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
});
>
# 6.建立完成後驗證是否可以登入
> db.auth("admin","password")
docker-compose 安裝
- docker-compose.yml
version: '3'
services:
mongodb:
image: mongo:4.4.2 # 映象:版本
container_name: mongo_db # 容器名
environment:
- MONGO_INITDB_ROOT_USERNAME=admin # root管理員賬戶
- MONGO_INITDB_ROOT_PASSWORD=password # root管理員密碼
- MONGO_INITDB_DATABASE=admin # 預設的資料庫
volumes:
- ./mongo/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
- ./mongo/mongo-volume:/data/db
ports:
- "27017-27019:27017-27019"
restart: always
- init-mongo.js
// db.getSiblingDB() 相當於 use admin;
db.getSiblingDB('admin').createUser({
user: 'user',
pwd: 'user',
roles: ['readWrite']
});
- 執行啟動命令即可
docker-compose up -d
**參考:**http://www.apgblogs.com/docker-mongodb/#4mongoDb
賬戶及許可權管理
注意:安裝好MongoDB資料庫後,預設是**【非授權模式】**(也就是不需要任何許可權驗證、不需要驗證賬戶,直接輸入 mongo 命令就可以進行相關操作)
所以:為了資料的安全,我們都應該去配置資料庫的訪問許可權 和 修改預設(mongodb://127.0.0.1:27017)連線繫結IP 和 埠號!
MongoDB是基於角色的訪問控制,所以建立使用者需要指定使用者的角色,在建立使用者之前需要滿足:
- 先在admin資料庫中建立角色為 userAdmin 或 userAdminAnyDatabase 的使用者作為管理使用者的使用者
- 啟用訪問控制,進行登入使用者驗證,這樣建立使用者才有意義
0、使用者角色介紹
資料庫角色分類(Built-In Roles—內建角色):
- 資料庫使用者角色:read、readWrite
- 資料庫管理角色:dbAdmin、dbOwner、userAdmin
- 叢集管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
- 備份恢復角色:backup、restore
- 所有資料庫角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
- 超級使用者角色:root
- 內部角色:__system
- 這幾個角色直接或間接提供系統超級使用者的訪問許可權:dbOwner 、userAdmin、userAdminAnyDatabase
各角色說明:
-
read:允許使用者讀取指定資料庫
-
readWrite:允許使用者讀寫指定資料庫
-
dbAdmin:允許使用者在指定資料庫中執行管理函式,如索引建立、刪除,檢視統計或訪問 system.profile
-
userAdmin:允許使用者向 system.users 集合寫入,可以找指定資料庫裡建立、刪除和管理使用者
-
clusterAdmin:只在 admin 資料庫中可用,賦予使用者所有分片和複製集相關函式的管理許可權
-
readAnyDatabase:只在 admin 資料庫中可用,賦予使用者所有資料庫的讀許可權
-
readWriteAnyDatabase:只在 admin 資料庫中可用,賦予使用者所有資料庫的讀寫許可權
-
userAdminAnyDatabase:只在 admin 資料庫中可用,賦予使用者所有資料庫的 userAdmin 許可權
-
dbAdminAnyDatabase:只在 admin 資料庫中可用,賦予使用者所有資料庫的 dbAdmin 許可權
-
root:只在 admin 資料庫中可用。超級賬號,超級許可權
-
MongoDB資料庫中的內建角色:
(1)、【資料庫使用者角色】針對每一個資料庫進行控制。
read:提供了讀取所有非系統集合,以及系統集合中的system.indexes, system.js, system.namespaces
readWrite:包含了所有read許可權,以及修改所有非系統集合的和系統集合中的system.js的許可權.
(2)、【資料庫管理角色】每一個資料庫包含了下面的資料庫管理角色。
dbOwner:該資料庫的所有者,具有該資料庫的全部許可權。
dbAdmin:一些資料庫物件的管理操作,但是沒有資料庫的讀寫許可權。(參考:http://docs.mongodb.org/manual/reference/built-in-roles/#dbAdmin)
userAdmin:為當前使用者建立、修改使用者和角色。擁有userAdmin許可權的使用者可以將該資料庫的任意許可權賦予任意的使用者。
(3)、【叢集管理許可權】admin資料庫包含了下面的角色,使用者管理整個系統,而非單個資料庫。這些許可權包含了複製集和共享叢集的管理函式。
clusterAdmin:提供了最大的叢集管理功能。相當於clusterManager, clusterMonitor, and hostManager和dropDatabase的許可權組合。
clusterManager:提供了叢集和複製集管理和監控操作。擁有該許可權的使用者可以操作config和local資料庫(即分片和複製功能)
clusterMonitor:僅僅監控叢集和複製集。
hostManager:提供了監控和管理伺服器的許可權,包括shutdown節點,logrotate, repairDatabase等。
備份恢復許可權:admin資料庫中包含了備份恢復資料的角色。包括backup、restore等等。
(4)、【所有資料庫角色】
admin:資料庫提供了一個mongod例項中所有資料庫的許可權角色:
readAnyDatabase:具有read每一個資料庫許可權。但是不包括應用到叢集中的資料庫。
readWriteAnyDatabase:具有readWrite每一個資料庫許可權。但是不包括應用到叢集中的資料庫。
userAdminAnyDatabase:具有userAdmin每一個資料庫許可權,但是不包括應用到叢集中的資料庫。
dbAdminAnyDatabase:提供了dbAdmin每一個資料庫許可權,但是不包括應用到叢集中的資料庫。
(5)、【超級管理員許可權】
root: dbadmin到admin資料庫、useradmin到admin資料庫以及UserAdminAnyDatabase。但它不具有備份恢復、直接操作system.*集合的許可權,但是擁有root許可權的超級使用者可以自己給自己賦予這些許可權。
(6)、【備份恢復角色】
backup:資料庫備份
restore:資料庫恢復
(7)、【內部角色】
__system
1、建立管理員使用者
啟用訪問控制登入之前,首先需要在admin資料庫中建立角色為userAdmin或userAdminAnyDatabase作為使用者管理的使用者,之後才能通過這個使用者建立其它角色的使用者,這個使用者作為其它所有使用者的管理者。
> # 1.切換admin資料庫
> use admin
> # 2.新增管理員使用者:user/pwd 分別代表使用者名稱和密碼,role 代表角色,db 代表要設定的資料庫。
> db.createUser({user:"admin", pwd:"password", roles:[{role: "userAdminAnyDatabase", db: "admin" }]})
> db.createUser({
user: "admin",
pwd: "password",
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
}
)
Successfully added user: {
"user" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
2、開啟授權訪問控制
要開啟訪問控制,則需要在mongod程式啟動時加上選項--auth
或在啟動配置檔案加入選項auth=true
,並重啟mongodb例項。
Windows 環境下
方式一:配置檔案方式啟動
MongoDB資料庫的相關配置資訊,是儲存在mongodb安裝目錄bin目錄中的mongod.cfg檔案中,
- 找到
mongod.cfg
檔案,然後增加如下配置:
# 開啟資料庫訪問許可權驗證(注意:換行、縮排格式哦!!)
security:
authorization: enabled
- 然後重新啟動MongoDB服務.
方式二:啟動時新增授權引數(以管理員身份啟動CMD)
# 先關閉MongoDB服務,然後移除,最後重新安裝MongoDB服務,帶上--auth引數
net stop MongoDB
mongod --remove
mongod --config "D:\Environment\MongoDB\Server\4.4\bin\mongod.cfg" --install --auth
net start MongoDB
Linux 環境下
方式一:配置檔案方式啟動
# 1.mongod配置檔案追加如下配置:
$ echo "auth=true" >> /usr/local/mongodb/bin/mongodb.conf
# 2.啟動mongodb例項
$ mongod --conf mongodb.cnf
# 3.使用mongo shell登入mongodb例項:
$ mongo 127.0.0.1:27017
MongoDB shell version v4.0.9
connecting to: mongodb://192.168.58.2:27017/test?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("428c215c-2927-49ee-8507-573efc4a1185") }
MongoDB server version: 4.0.9
>
# 如果沒有開啟訪問控制,則在登入時會提示如下警告資訊
** WARNING: Access control is not enabled for the database.
** Read and write access to data and configuration is unrestricted.
方式二:啟動時新增授權引數
# 前臺啟動
mongod --dbpath /usr/local/mongodb/data --auth
# 後臺啟動
mongod --dbpath /usr/local/mongodb/data --logpath /usr/local/mongodb/logs/mongodb.log --fork --auth
3、使用者認證登陸
注:重新啟動mongodb服務後,用一個新的命令視窗來做操作,在配置賬戶許可權後,直接在命令視窗中用 mongo 命令,執行相關的操作是沒有響應的,只有在正確的輸入賬戶和密碼後才進行相關操作!!
可以在使用mongo shell登入時新增選項--authenticationDatabase
或登入完後在admin資料庫下進行驗證。
- 在mongo shell登入時同時進行驗證:
$ mongo 127.0.0.1:27017 -uuser_admin -p --authenticationDatabase admin
MongoDB shell version v4.0.9
Enter password: # 輸入密碼admin
connecting to: mongodb://192.168.58.2:27017/test?authSource=admin&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("94663b8d-7d88-4c97-ad1c-c3c24262ad39") }
MongoDB server version: 4.0.9
>
- mongo shell 登入完成之後進行驗證:
$ mongo 127.0.0.1:27017
MongoDB shell version v4.0.9
connecting to: mongodb://192.168.58.2:27017/test?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("531e75df-3a5d-4f35-9e18-d7a6e090df63") }
MongoDB server version: 4.0.9
> use admin
switched to db admin
> # 登入認證,返回1,代表登入成功
> db.auth('user_admin','admin')
1
- 連線本地MongoDB資料庫(不指定IP 和埠號):
mongo -u admin -p password
- 連線遠端MongoDB資料庫(指定IP 和 埠號):
- 不指定資料庫名(沒有輸入賬號登入):
mongo --host 127.0.0.1 --port 27017
- 不指定資料庫名(輸入賬號登入):
mongo --host 127.0.0.1 --port 27017 -u admin -p password
- 指定登入資料庫(輸入賬號登入):
mongo 127.0.0.1:27017/admin -u admin -p password
- 不指定資料庫名(沒有輸入賬號登入):
4、建立普通使用者
注:各個不同的資料庫之間,可以建立有一個 或 多個賬戶,各資料庫之間賬戶、密碼都是獨立的,不能互相訪問!
- 使用admin使用者在admin資料庫中建立基於角色dbOwner的使用者test
# 方式一:
# customData 內可以設定任何描述該使用者的資訊
> use admin
> db.createUser({
user: "test",
pwd: "password",
roles: [{role: "dbOwner", db: "test"}],
customData: {info: "user for dbOwner"}
}
)
# 方式二:
> db.getSiblingDB("admin").runCommand({
createUser: "test",
pwd: "password",
roles: [{role: "dbOwner", db: "test"}],
customData: { info: "user for dbOwner"}
}
)
{ "ok" : 1 }
- 登入test資料庫給建立test使用者,並且賦予該使用者許可權
> use test
> db.createUser({
user: "test_admin",
pwd: "password",
roles: [
{role: "read", db: "test"},
{role: "readWrite", db: "test"}]
})
5、檢視使用者資訊
1、查詢當前資料庫的指定使用者:db.getUser(‘使用者名稱’, args)
2、檢視當前資料庫的所有使用者:db.getUsers()、show users
引數說明:
Field | Type | Description |
---|---|---|
showCredentials | boolean | 可選的。將欄位設定為 true 以顯示使用者的密碼雜湊。預設情況下,此欄位為false 。 |
showPrivileges | boolean | 可選的。將欄位設定為 true 以顯示使用者的完整特權集,包括繼承角色的擴充套件資訊。預設情況下,此欄位為false 。如果檢視所有使用者,則不能指定此欄位。 |
showAuthenticationRestrictions | boolean | 可選的。將欄位設定為 true 以顯示使用者的身份驗證限制。預設情況下,此欄位為false 。如果檢視所有使用者,則不能指定此欄位。 |
- 查詢指定使用者
# 方式一:
> use admin
> db.getUser("admin", { showPrivileges: true })
# 方式二:
> db.getSiblingDB("admin").runCommand({
usersInfo: "admin",
showPrivileges: true
}
)
- 查詢所有使用者:
> show users
{
"_id" : "admin.admin",
"userId" : UUID("f4000321-33d7-43bd-b791-a42294c4a004"),
"user" : "admin",
"db" : "admin",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
}
{
"_id" : "admin.test",
"userId" : UUID("c6788e01-a812-4bb8-8d57-0553731e27c4"),
"user" : "test",
"db" : "admin",
"roles" : [
{
"role" : "dbOwner",
"db" : "test"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
}
6、更新使用者資訊
updateuser()它是完全替換之前的值:
如果要新增或新增roles而不是代替它 則使用方法: db.grantRolesToUser() 和 db.revokeRolesFromUser()
如果只是更新密碼也可以只用此方式:db.changeUserPassword()
更新使用者 test 具有 admin 資料庫 readWrite 角色為read角色。
> use admin
> db.updateUser("test",{
customData: { info: "user for test" },
roles: [{role: "read", db: "test" }]
})
> use admin
> db.runCommand({
updateUser: "test",
roles: [{ role: "read", db: "test" }],
customData: { info: "user for test" }
})
7、更新使用者角色
1、db.grantRolesToUser()
:為使用者增加角色
2、db.revokeRolesFromUser()
:為使用者回收角色
- 為使用者test新增admin資料庫的readWrite角色。
# 方式一:
> use admin
> db.grantRolesToUser("test",
[
{role: "readWrite", db: "admin"},
{role: "dbOwner", db: "admin"}
]
)
# 方式二:
> use admin
> db.runCommand({
grantRolesToUser: "test",
roles:
[
{role: "readWrite", db: "admin" },
{role: "dbOwner", db: "admin" }
]
}
)
- 使用者dbabd_user回收admin資料庫的read角色。
# 方式一:
> use admin
> db.revokeRolesFromUser("test", [{ role: "dbOwner", db: "test"}])
# 方式二:
> use admin
> db.runCommand({
revokeRolesFromUser: "test",
roles:[{ role: "dbOwner", db: "test"}]
})
8、更改使用者密碼
-
db.updateUser('username',{'pwd':'newpassword'})
。必須有使用者管理許可權才能使用。這個方式不止可以更新密碼。 -
db.changeUserPassword('username','newpassword')
。必須有使用者管理全出現才能使用
use admin
db.changeUserPassword("addmin", "admin123")
>
use admin
db.updateUser('addmin',{'pwd':'admin123'})
9、刪除使用者
use admin
db.dropUser("test")
>
use admin
db.runCommand({ dropUser: "test" })
資料庫操作
1、資料庫命名規則
MongoDB 資料庫的命名要符合 UTF-8 標準的字串,同時要遵循下表所示的注意事項。
序號 | 注意事項 |
---|---|
1 | 不能是空串 |
2 | 不得含有 /、\、?、$、空格、空字元等,基本只能使用 ASCII 中的字母和數字 |
3 | 區分大小寫,建議全部小寫 |
4 | 名稱最多為 64 位元組 |
5 | 不得使用保留的資料庫名,如:admin、local、config |
注意:資料庫最終會成為檔案,資料庫名就是檔案的名稱。
- 由於資料庫名稱在 MongoDB 中不區分大小寫,因此資料庫名稱不能僅僅區別於字元。
- 對於在 Windows 上執行的 MongoDB,資料庫名稱不能包含以下字元:/、\、“、$、*、< >、:、|、? 。
- 對於在 UNIX 和 Linux 系統上執行的 MongoDB,資料庫名稱不能包含以下字元:/、\、。、"、$。
- 雖然 UTF-8 可以提供很多國家的語言的命名格式,在 MongoDB 資料庫命名時也可以使用漢字作為資料庫名,但是最好儘量採用英文字母、數字、字元等為主的命名格式。
示例:
-
正確的命名格式:myDB、my_NewDB、myDB12
-
錯誤的命名格式:.myDB、/123
保留資料庫:MongoDB 系統保留的資料庫如下:
庫名 | 作用 |
---|---|
admin | 許可權資料庫,新增使用者到該資料庫中,該使用者會自動繼承資料庫的所有許可權 |
local | 資料庫中的資料永遠不會被複制 |
config | 分片時,config 資料庫在內部使用,儲存分子資訊 |
test | 預設資料庫,可以用來做各種測試等 |
2、建立切換資料庫
建立、開啟、切換 資料庫:use dbname
use
> use mydb
switched to db mydb
注:
- 如果開啟的這個資料庫存在就是開啟這個資料庫。
- 如果開啟的是一個不存在的資料庫(沒有這個資料庫名字),那麼就會建立一個同名的資料庫。
- 建立一個新的資料庫時,需要向資料庫中建立集合並且插入一條資料,這個資料庫才能建立成功!否則show dbs查詢不到此資料庫
示例:往集合中插入一條資料。可以不用先建立集合,直接往裡新增資料即可:
# user 就是集合(表)名
db.user.insert({"name": "xiaoming"})
當命令執行後,資料庫系統發現 user 是一個資料集合不存的,就自動建立一個集合,並隨著資料的插入,資料庫和集合也就真正的建立成功了。
要在不切換當前資料庫訪問其他的資料庫使用 db.getSiblingDB() 方法。
3、檢視資料庫
- 檢視當前所在資料庫(預設為test):
db
- 檢視所有資料庫:
show dbs
- 檢視當前資料庫相關資訊(名稱、文件個數、檢視、索引、大小等):
db.stats()
> db
test
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
>
> db.stats() # 統計資料資訊
{
"db" : "test", # 資料庫名
"collections" : 0, # 集合數量
"views" : 0,
"objects" : 0, # 文件數量
"avgObjSize" : 0, # 平均每個文件的大小
"dataSize" : 0, # 資料佔用空間大小,不包括索引,單位為位元組
"storageSize" : 0, # 分配的儲存空間
"totalSize" : 0, # 總共空間大小
"indexes" : 0, # 索引個數
"indexSize" : 0, # 索引佔用空間大小
"scaleFactor" : 1,
"fileSize" : 0,
"fsUsedSize" : 0,
"fsTotalSize" : 0,
"ok" : 1
}
**備註:**為什麼查詢所有資料庫時沒有看到當前預設的test資料庫呢?因為test資料庫內沒有資料,實際上不算真正意義上的存在。
4、刪除資料庫
刪除當前所在的資料庫:db.dropDatabase()
注:刪除後集閤中的所以文件、以及相關的索引等都會被刪除!!
> db.dropDatabase()
{ "ok" : 1 }
6、檢視幫助文件
1、資料庫幫助命令
-
匯入工具所有操作方法:
mongoexport --help
-
匯出工具所有操作方法:
mongoimport --help
-
備份工具所有操作方法:
mongodump --help
-
恢復工具所有操作方法:
mongorestore --help
-
列出MongoDB資料庫所有的操作方法:
db.help()
-
列出MongoDB文件(表)所有的操作方法:
db.collection.help()
集合操作
1、集合命名規則
MongoDB 的集合就相當於 MySQL 的一個表 table
,集合是一組文件,是無模式的,集合名稱要求符合 UTF-8 標準的字串,同時要遵循下表所示的注意事項。
序號 | 注意事項 |
---|---|
1 | 集合名不能是空串 |
2 | 不能含有空字元 \0 |
3 | 不能以“system.”開頭,這是系統集合保留的字首 |
4 | 集合名不能含保留字元“$” |
對於分別部署在 Windows、Linux、UNIX 系統上的 MongoDB,集合的命名方式與資料庫命名方式一致。
2、集合建立
MongoDB 集合的建立有顯式和隱式(推薦)兩種方法。
2.1、顯示建立集合函式:db.createCollection(name, options)
語法格式:db.createCollection(name,options)
name:要建立的集合名稱
options:可選引數,指定有關記憶體大小及索引的選項
- options 可以是如下引數:
引數 | 型別 | 描述 |
---|---|---|
capped | Boolean | (可選)如果為 true,則啟用封閉的集合。上限集合是固定大小的集合,它在達到其最大時自動覆蓋其最舊的條目。如果指定 true,則還需要指定 size 引數 |
autoindexid | Boolean | (可選)如果為 true,自動在 _id 欄位建立索引。預設為false。 |
size | 數字 | (可選)指定上限集合的最大大小(以位元組為單位)。如果 capped 為 true,那麼還需要指定此欄位的值 |
max | 數字 | (可選)指定上限集合中允許的最大文件數 |
- 建立無引數的集合:
db.createCollection('day1')
- 建立帶引數的集合:
# 建立名為day2的固定集合,集合空間大小為:2000000kb(大約1.9g),文件最大個數為:1000
db.createCollection('day2',{capped:true,autoIndexId:true,size:2000000,max:1000})
- 示例:
> db.createCollection('day1')
{ "ok" : 1 }
>
> db.createCollection('day2',{capped:true,autoIndexId:true,size:2000000,max:1000})
{
"note" : "The autoIndexId option is deprecated and will be removed in a future release",
"ok" : 1
}
> show collections
day1
day2
students
>
2.2、隱式建立集合(推薦):
當插入文件時,如果集合不存在,則 MongoDB會隱式地自動建立集合:
db.myDB.insert({"name": "tom"})
3、集合查詢
MySQL 列出的所有表都可以使用 show tables。MongoDB 列出所有集合可以使用如下兩種方式:
-
show tables
-
show collections
-
db.getCollectionNames()
> db
test
> show tables
dept
student
> show collections
dept
student
> db.getCollectionNames()
[ "dept", "student" ]
>
4、集合刪除
集合刪除(當前集合):db.collection.drop();
> db.day1.drop()
true
5、集合修改
集合重新命名:db.collection.renameCollection();
> db.students.renameCollection("student")
{ "ok" : 1 }
文件操作
1、文件命名規則
文件是 MongoDB 中儲存的基本單元,是一組有序的鍵值對集合。文件中儲存的文件鍵的格式必須是符合 UTF-8 標準的字串,同時要遵循以下注意事項:
- 不能包含
\0
字元(空字元),因為這個字元表示鍵的結束; - 不能包含
$
和.
,因為.
和$
是被保留的,只能在特定環境下使用; - 鍵名區分大小寫;
- 鍵的值區分型別(如字串和整數等);
- 鍵不能重複,在一條文件裡起唯一的作用。
**注意:**以上所有命名規範必須符合 UTF-8 標準的字串,文件的鍵值對是有順序的,相同的鍵值對如果有不同順序,也是不同的文件。
示例:
- 例1:以下兩組文件是不同的,因為值的型別不同。
{ "recommend" : "5" }
{ "recommend" : 5 }
- 例2:以下兩組文件也是不同的,因為鍵名是區分大小寫的。
{ "Recommend" : " 5 "}
{ "recommend" : "5" }
2、資料插入
注:插入資料時不需要專門去建立集合(表),因為插入資料時會自動建立集合!!
save():如果 _id 主鍵存在則更新資料,如果不存在就插入資料。該方法新版本中已廢棄,已使用 insertOne() 或 replaceOne() 來代替。
insert():若插入的資料主鍵已經存在,則會拋 org.springframework.dao.DuplicateKeyException 異常,提示主鍵重複,不儲存當前資料.
- db.collection.insert():在指定集合中插入一個或者多個文件
- db.collection.insertOne():在指定集合插入一個新文件
- db.collection.insertMany():在指定集合插入一個多個文件
db.collection.insert()
在平時的使用當中,**db.collection.insert()**是我用得最多的文件插入方式,具體的語法格式如下:
db.collection.insert(
<document or array of documents>,
{
writeConcern: <document>,
ordered: <boolean>
}
)
引數說明:
- document:指定寫入的文件,可以一個或多個
- writeConcern:寫入策略,預設為 1,即要求確認寫操作,0 是不要求
- ordered:指定是否按順序寫入(可選),預設 true
- 當指定為true時,插入多個文件時將文件排序儲存在一個陣列中進行插入,如果其中有一個文件插入失敗,則會導致陣列中餘下的文件不進行插入操作;
- 當指定為false時,插入多個文件時將文件不進行排序儲存在一個陣列中進行插入,如果其中有一個文件插入失敗,則不影響陣列中餘下的文件進行插入操作。
如果插入的文件當中沒有指定_id
欄位,則MongoDB會自動為文件生成具有唯一ObjectId
值的欄位_id
。
示例:
// insert 插入一條資料
db.student.insert({"name": "zhangsan", "age": 28, addr: "ShenZhen"});
// insert 插入一條資料,並指定_id
db.student.insert({_id: 1, "name": "zhangsan", "age": 28, addr: "ShenZhen"});
// insert 插入多條資料,不進行排序
db.student.insert([
{"name": "zhangsan", "age": 32, addr: "GuangZhou"},
{"name": "wangwu", "age": 16, addr: "ShangHai"}
]);
// insert 插入多條資料,並進行排序
db.student.insert(
[
{"name": "zhangsan", "age": 32, addr: "GuangZhou"},
{"name": "wangwu", "age": 16, addr: "ShangHai"}
],
{ordered: false}
);
db.collection.insertOne() 與 db.collection.insertMany()
語法格式如下:
// 單行插入
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
// 多行插入
db.collection.insertMany(
[ <document1> , <document2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
- 引數說明:
- document:要寫入的文件。
- writeConcern:寫入策略,預設為 1,即要求確認寫操作,0 是不要求。
- ordered:指定是否按順序寫入,預設 true,按順序寫入。
使用示例:
// 單行插入文件,關於_id欄位指定與否也與db.collection.insert()一致
db.student.insertOne({"name": "zhangsan", "age": 28, addr: "ShenZhen"});
// 插入多條資料
db.student.insertMany([
{"name": "zhangsan", "age": 32, addr: "GuangZhou"},
{"name": "wangwu", "age": 16, addr: "ShangHai"}
]);
關於返回確認資訊
> # insert 插入一條資料
> db.student.insert({"name": "zhangsan", "age": 28, addr: "ShenZhen"});
WriteResult({ "nInserted" : 1 })
>
> # insert 插入多條資料
> db.student.insert([
... {"name": "zhangsan", "age": 32, addr: "GuangZhou"},
... {"name": "wangwu", "age": 16, addr: "ShangHai"}
... ]);
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
>
> # 插入1條資料
> db.student.insertOne({"name": "zhangsan", "age": 28, addr: "ShenZhen"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5fd4c7676817e7a0fa646b85")
}
>
> # 插入多條資料
> db.student.insertMany([
... {"name": "zhangsan", "age": 32, addr: "GuangZhou"},
... {"name": "wangwu", "age": 16, addr: "ShangHai"}
... ]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5fd4c7706817e7a0fa646b86"),
ObjectId("5fd4c7706817e7a0fa646b87")
]
}
>
3、資料查詢
查詢(Read Operations)讀操作,是對集合中已存在的文件進行查詢,即對應關係型資料庫當中的select
操作,MongoDB提供以下幾種主要查詢文件方法:
- db.collection.find():查詢指定集合中滿足條件的一個或多個文件和檢視;
- db.collection.findOne():查詢指定集合中滿足條件的第一個文件
- ***.pretty():**以格式化方式展現,通過
pretty()
方法
插入測試資料
db.user.insert([
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" },
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "GuangZhou" },
{ "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" },
{ "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" },
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "ShenZhen" },
{ "_id" : 6, "name" : "LiSi", "age" : 20, "addr" : "HangZhou" }
])
此時 user
表中的資料列表如下:
id | name | age | addr |
---|---|---|---|
1 | ZhangSan | 25 | ShenZhen |
2 | XiaoMing | 27 | GuangZhou |
3 | LaoWan | 30 | BeiJing |
4 | WangWu | 32 | ShangHai |
5 | ZhaoSi | 28 | ShenZhen |
6 | LiSi | 20 | HangZhou |
db.collection.find() 與 db.collection.findOne()
db.collection.find() :是使用頻率最高的方法了,可以用來查詢資料庫集合當中的文件
db.collection.findOne():方法顯示符合條件查詢的第一條文件
語法格式如下:
db.collection.find(<query>, <projection>)
db.collection.findOne(<query>, <projection>)
- query:查詢表示式;
- projection:指定查詢結果集中需要顯示的欄位。
- Col_name:1|true 代表顯示該欄位;
- Col_name:0 | false 代表不顯示該欄位。
_id 欄位是預設顯示的,如果不想顯示,則顯式指定 {"_id" : 0}
使用示例:
// 查詢全部資料的兩種方式
db.collection.find()
db.collection.find({})
// 查詢單個文件:
db.collection.findOne()
//============================查詢所有文件資料============================
> db.user.find()
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "GuangZhou" }
{ "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" }
{ "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" }
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "ShenZhen" }
{ "_id" : 6, "name" : "LiSi", "age" : 20, "addr" : "HangZhou" }
//============================查詢單個文件資料============================
> db.user.findOne({addr: "ShenZhen"})
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
指定返回欄位
db.getCollection('user').find(用於過濾記錄的字典,用於限定欄位的字典)
- 如果值為0,則表示在全部欄位中剔除值為0的這些欄位並返回。
- 如果值為1,則表示只返回值為1的這些欄位。(預設都為1,顯示)
使用示例:
// 只顯示name欄位和age欄位
db.user.find({},{ name : 1 , age : 1 }).limit(1)
{ "_id" : 1, "name" : "ZhangSan", "age" : 25 }
// 不顯示_id欄位和name欄位,其他欄位都顯示
db.user.find({},{ _id : 0 , name : 0 }).limit(1)
{ "age" : 25, "addr" : "ShenZhen" }
注意:不能0(顯示欄位)和1(剔除欄位)在同一個語句中一起使用,不然會報錯
範圍操作符
名稱 | 操作 | 格式 | 範例 | RDBMS中的類似語句 |
---|---|---|---|---|
$eq | 等於 | {:} | db.col.find({“by”:“Mongo教程”}) | where by = ‘Mongo教程’ |
$lt | 小於 | {:{$lt:}} | db.col.find({“likes”:{$lt:50}}) | where likes < 50 |
$te | 小於或等於 | {:{$lte:}} | db.col.find({“likes”:{$lte:50}}) | where likes <= 50 |
$gt | 大於 | {:{$gt:}} | db.col.find({“likes”:{$gt:50}}) | where likes > 50 |
$gte | 大於或等於 | {:{$gte:}} | db.col.find({“likes”:{$gte:50}}) | where likes >= 50 |
$ne | 不等於 | {:{$ne:}} | db.col.find({“likes”:{$ne:50}}) | where likes != 50 |
$in | 指定值在陣列中 | {:{$in:[]}} | db.col.find({“likes”:{$in:[50]}}) | where likes in (50) |
$nin | 指定值不在陣列中 | {:{$nin:[]}} | db.col.find({“likes”:{$nin:[50]}}) | where likes not in (50) |
使用示例:
// $eq:等值查詢 SQL: SELECT * FROM user WHERE name = "XiaoHei";
db.user.find( { name: "ZhangSan" } )
// $ne:等值查詢 SQL: SELECT * FROM user WHERE name != "XiaoHei";
db.user.find( { name: {$ne: "XiaoHei"} } )
// $gt:範圍查詢(以大於為例) SQL: SELECT * FROM user WHERE age > 30;
db.user.find( { age: {$gt: 30} } )
// $gte、$lt、$lte 同$gt
// $in:或查詢,可使用or代替 SQL: SELECT * FROM user WHERE addr in ("ShenZhen", "GuangZhou")
db.user.find( { addr: { $in: [ "ShenZhen", "GuangZhou" ] } } )
// $nin:SQL: SELECT * FROM user addr not in ("BeiJing")
db.user.find( { addr: { $nin: [ "BeiJing"] } } )
邏輯操作符
名稱 | 說明 |
---|---|
$and | 指定查詢同時滿足多個條件查詢子句(預設) |
$not | 指定查詢不滿足條件查詢子句 |
$or | 指定查詢滿足其中某個條件查詢子句 |
$nor | 指定查詢無法滿足多個條件查詢子句 |
使用例項:
// $and: 邏輯與查詢 SQL: SELECT * FROM user WHERE addr = "ShenZhen" AND age < 30;
db.user.find( { $and: [ { addr: { $eq: "ShenZhen" }, age: { $lt: 30 } } ] } )
// $and: 或者(一般這種形式更加常用,$and 和 $eq 預設可以省略)
db.user.find( { addr: "ShenZhen", age: { $lt: 30 } } )
// $not: 不符合查詢 SQL: SELECT * FROM user WHERE addr <> "GuangZhou";
db.user.find( { addr: { $not: { $eq: "GuangZhou" } } } )
// $or: 邏輯或查詢 SQL: SELECT * FROM user WHERE addr = "GuangZhou" OR age < 30;
db.user.find( { $or: [ { addr: "GuangZhou" }, { age: { $lt: 30 } } ] } )
/*
$nor: 無法同時滿足多個條件查詢,欄位不存在時也符合
SQL: SELECT * FROM user WHERE addr <> "GuangZhou" AND age > 30;
符合以下條件之一都會出現在結果集中:
1.文件包含addr和age欄位並且符合條件;
2.文件包含addr欄位並且符合條件,不包含age欄位;
3.文件不包含addr欄位,包含age欄位並且符合條件;
4.文件不包含addr欄位和age欄位。
*/
db.user.find( { $nor: [ { addr: { $ne: "GuangZhou" } }, { age: { $gt: 30 } } ] } )
元素操作符
名稱 | 說明 |
---|---|
$exists | 指定查詢文件是否有對應的欄位 |
$type | 指定查詢文件的某個欄位是否是對應型別 |
使用示例:
// $exists: 是否存在指定欄位查詢,返回所有存在該欄位的資料
db.user.find( { name: { $exists: true } } )
// $type: 欄位是否是指定型別查詢,返回所有age欄位為double的資料
db.user.find( { "age": { $type: "double" } } )
評估操作符
參考官方文件:https://docs.mongodb.com/manual/reference/operator/query-evaluation/
名稱 | 說明 |
---|---|
$expr | 為同一個文件中的欄位指定表示式並且符合條件的查詢,比如比較同一文件當中兩個欄位的值 |
$mod | 為欄位值取模並且符合條件的查詢 |
為了更好的使用這兩個主要的操作符,額外建立個文件:
db.monthlyBudget.insertMany([
{ "_id" : 1, "category" : "food", "budget": 400, "spent": 450 },
{ "_id" : 2, "category" : "drinks", "budget": 100, "spent": 150 },
{ "_id" : 3, "category" : "clothes", "budget": 100, "spent": 50 },
{ "_id" : 4, "category" : "misc", "budget": 500, "spent": 300 },
{ "_id" : 5, "category" : "travel", "budget": 200, "spent": 650 }
]);
使用示例:
// $expr: 允許使用聚合表示式,這裡以$gt為例,更多表示式參考:
// https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#aggregation-expressions
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )
// $mod: 對欄位所在值進行取模運算,顯示符合條件的查詢,如qty欄位值對4取模,並且餘數為0
db.inventory.find( { qty: { $mod: [ 4, 0 ] } } )
查詢結果修飾
db.collection.find().count()
db.collection.find().limit(number)
db.collection.find().skip(number)
db.collection.find().sort({key, 1或-1})
db.collection.find().distinct()
(1)查詢當前集合資料量:db.collection.find().count()
(2)查詢集合前幾條資料:db.collection.find().limit(number)
(3)限定跳過前幾條結果:db.collection.find().skip(number)
(4)對查詢結果進行排序:db.collection.find().sort(key, 1或-1)
(5)對查詢結果進行去重:db.collection.distinct()
使用示例:
// 相當於select count(1) from user
> db.user.find().count()
6
// 查詢前 1 條資料
// 相當於:SELECT * FROM user limit 10
> db.user.find().limit(1)
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
// 查詢第 5 條以後的資料
> db.user.find().skip(5)
{ "_id" : 6, "name" : "LiSi", "age" : 20, "addr" : "HangZhou" }
/*
* 查詢 10 到 20 之間的資料
* 列表分頁
* limit:就是 pageSize
* skip :就是第幾頁 * pageSize
*/
> db.user.find().limit(20).skip(10);
// 查詢某個結果集的記錄條數(統計數量)
// 相當於:select count(*) from user where age >= 18;
db.user.find({age: {$gte: 18}}).count();
// 如果要返回限制之後的記錄數量,要使用 count(true)或者 count(非 0)
db.user.find().limit(20).skip(10).count(true);
// 1為升序,-1為降序
> db.user.find().sort({"age": -1});
{ "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" }
{ "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" }
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "ShenZhen" }
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "GuangZhou" }
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
{ "_id" : 6, "name" : "LiSi", "age" : 20, "addr" : "HangZhou" }
> db.user.distinct('age', { 'age':{'$gte':25 } } )
[ 25, 27, 28, 30, 32 ]
4、聚合查詢
聚合查詢
MongoDB聚合框架(Aggregation Framework)是一個計算框架,它可以:
- 可作用在一個 或 幾個集合上
- 對集合中的資料進行一系列的運算
- 可將資料轉化為所期望資料形式,如(數學計算,統計,型別,格式處理等)
對效果而言,聚合查詢相錄於傳統SQL查詢中的,ORDER BY,GROUP BY,LIMIT,LEFT OUTER JOIN,AS等!
- 聚合查詢對照:(MongoDB 與 傳統資料庫 比對)
步驟 | 作用 | SQL等價運算子 |
---|---|---|
$match | 過濾 | where / having |
$group | 分組 | group by |
$project | 投影(別名) | as |
$limit | 結果限制 | limit |
$skip | 結果限制 | skip |
$sort | 排序 | order by |
$lookup | 左外連線(多表操作) | left outer join |
$graphLookup | 圖搜尋 | N/A |
$facet | 分面搜尋 | N/A |
$bucket | 分面搜尋 | N/A |
$unwind | 展開陣列 | N/A |
Aggregate簡介
db.collection.aggregate() 是基於資料處理的聚合管道,每個文件通過一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組、過濾等功能,然後經過一系列的處理,輸出相應的結果。
通過這張圖,可以瞭解Aggregate處理的過程:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-BhkZxD8C-1609051910735)(MongoDB快速入門/20201212120353.png)]
db.user.aggregate([
{ $match : { age : 20 } }, ==》$match stage
{ $group: { _id: '$addr', total: { $sum: '$age' } } } ==》$group stage
])
====================================================================
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "ShenZhen" }
{ "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" }
{ "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" }
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "GuangZhou" }
{ "_id" : 6, "name" : "LiSi", "age" : 30, "addr" : "HangZhou" }
{ "_id" : 7, "name" : "KaiFa", "age" : 20, "addr" : "HangZhou" }
{ "_id" : 8, "name" : "QianDuan", "age" : 40, "addr" : "HangZhou" }
{ "_id" : 9, "name" : "YunWei", "age" : 20, "addr" : "GuangZhou" }
{ "_id" : 10, "name" : "CeSi", "age" : 20, "addr" : "GuangZhou" }
===================================================================
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
$match
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
====================================================================
{ "_id" : 7, "name" : "KaiFa", "age" : 20, "addr" : "HangZhou" }
{ "_id" : 9, "name" : "YunWei", "age" : 20, "addr" : "GuangZhou" }
{ "_id" : 10, "name" : "CeSi", "age" : 20, "addr" : "GuangZhou" }
====================================================================
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
$group
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
===========================Results==================================
{ "_id" : "HangZhou", "total" : 20 }
{ "_id" : "GuangZhou", "total" : 40 }
===========================Results==================================
1、db.collection.aggregate() 可以用多個構件建立一個管道,對於一連串的文件進行處理。這些構件包括:篩選操作的match、對映操作的project、分組操作的group、排序操作的sort、限制操作的limit、和跳過操作的skip。
2、db.collection.aggregate()使用了MongoDB內建的原生操作,聚合效率非常高,支援類似於SQL Group By操作的功能,而不再需要使用者編寫自定義的JavaScript例程。
3、 每個階段管道限制為100MB的記憶體。如果一個節點管道超過這個極限,MongoDB將產生一個錯誤。為了能夠在處理大型資料集,可以設定allowDiskUse為true來在聚合管道節點把資料寫入臨時檔案。這樣就可以解決100MB的記憶體的限制。
4、db.collection.aggregate()可以作用在分片集合,但結果不能輸在分片集合,MapReduce可以 作用在分片集合,結果也可以輸在分片集合。
5、db.collection.aggregate()方法可以返回一個指標(cursor),資料放在記憶體中,直接操作。跟Mongo shell 一樣指標操作。
6、db.collection.aggregate()輸出的結果只能儲存在一個文件中,BSON Document大小限制為16M。可以通過返回指標解決,版本2.6中後面:DB.collect.aggregate()方法返回一個指標,可以返回任何結果集的大小。
Aggregate語法
db.collection.aggregate(pipeline, options)
引數說明:
引數 | 型別 | 描述 |
---|---|---|
pipeline | array | 一系列資料聚合操作或階段。詳見聚合管道操作符 在版本2.6中更改:該方法仍然可以將流水線階段作為單獨的引數接受,而不是作為陣列中的元素;但是,如果不將管道指定為陣列,則不能指定options引數 |
options | document | 可選。 aggregate()傳遞給聚合命令的其他選項。 2.6版中的新增功能:僅當將管道指定為陣列時才可用。 |
**注意:**使用db.collection.aggregate()
直接查詢會提示錯誤,但是傳一個空陣列如db.collection.aggregate([])
則不會報錯,且會和find一樣返回所有文件。
pipeline有很多stage,但這裡我只記錄我經常用到的幾個,如果後續用到再補充。stage詳見官網。
接下來介紹這幾個常用的stage
aggregate常用pipeline stage介紹
準備測試資料:
db.getCollection("user").drop()
db.getCollection("user").insert([
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" },
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "ShenZhen" },
{ "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" },
{ "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" },
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "GuangZhou" },
{ "_id" : 6, "name" : "LiSi", "age" : 30, "addr" : "HangZhou" },
{ "_id" : 7, "name" : "KaiFa", "age" : 20, "addr" : "HangZhou" },
{ "_id" : 8, "name" : "QianDuan", "age" : 40, "addr" : "HangZhou" },
{ "_id" : 9, "name" : "YunWei", "age" : 20, "addr" : "GuangZhou" },
{ "_id" : 10, "name" : "CeSi", "age" : 20, "addr" : "GuangZhou" }
])
操作示例: m a t c h 、 match、 match、count、 l i m i t 、 limit、 limit、skip、 s o r t 、 sort、 sort、project
// 執行:
// 1)$match 階段排除age小於等於80的文件,將大於80的文件傳到下個階段
// 2)$count階段返回聚合管道中剩餘文件的計數,並將該值分配給名為age_count的欄位。
> db.getCollection("user").aggregate([
{ $match : { age : { $gt: 25} } },
{ $count : "age_count" }
])
{ "age_count" : 6 }
// 1.$skip和$limit 查詢6-10條資料
// 2.首先按照age降序排序,然後按照_id降序排序
// 3.給name、age、addr 欄位取別名
> db.getCollection("user").aggregate([
{ $skip : 5 },
{ $limit : 9 },
{ $sort : { age : -1 , _id : -1}},
{ $project : {
'姓名': '$name',
'年齡': '$age',
'地址': '$addr'
}}
])
{ "_id" : 8, "姓名" : "QianDuan", "年齡" : 40, "地址" : "HangZhou" }
{ "_id" : 6, "姓名" : "LiSi", "年齡" : 30, "地址" : "HangZhou" }
{ "_id" : 10, "姓名" : "CeSi", "年齡" : 20, "地址" : "GuangZhou" }
{ "_id" : 9, "姓名" : "YunWei", "年齡" : 20, "地址" : "GuangZhou" }
{ "_id" : 7, "姓名" : "KaiFa", "年齡" : 20, "地址" : "HangZhou" }
聚合分組($group)的表示式:
語法:
{
$group:
{
_id: <expression>,
<field1>: {
<accumulator1> : <expression1>
},
<field2>: {
<accumulator2> : <expression2>
},
...
}
}
- _id欄位是必填的,但是可以指定_id值為null來為整個輸入文件計算累計值。
- 剩餘的計算欄位是可選的,並使用<accumulator>運算子進行計算。
- _id和<accumulator>\表示式可以接受任何有效的表示式。
示例:
[
{
$group: {
_id: {
addr: '$addr'
},
totalCount: {
$sum: 1
}
}
}
]
$group
是固定的,表示這裡一個分組聚合操作。_id
表示需要根據哪一些列進行聚合,其實一個JSON物件,其key/value對分別表示結果列的別名以及需要聚合的的資料庫列。totaoCount
表示聚合列的列名。$sum
表示要進行的聚合操作,後面的1表示每次加1。
accumulator操作符
表示式 | 描述 | 例項 |
---|---|---|
$sum | 計算總和。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}]) |
$avg | 計算平均值 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}]) |
$min | 獲取集合中所有文件對應值得最小值。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}]) |
$max | 獲取集合中所有文件對應值得最大值。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}]) |
$push | 在結果文件中插入值到一個陣列中。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}]) |
$addToSet | 在結果文件中插入值到一個陣列中,但不建立副本。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}]) |
$first | 根據資源文件的排序獲取第一個文件資料。 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}]) |
$last | 根據資源文件的排序獲取最後一個文件資料 | db.col.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}]) |
使用示例: s u m 、 sum、 sum、avg、 m a x 、 max、 max、min、 f i r s t 、 first、 first、last
// 地址分組統計:個數、總和、平均數、最大、最小、首個、最後一個
db.getCollection("user").aggregate([{
$group: {
_id: { userAddr: '$addr' },
totalCount: { $sum: 1 },
ageSum: { $sum: '$age' },
ageAvg: { $avg: '$age' },
ageMax: { $max: '$age' },
ageMin: { $min: '$age' },
ageFirst: { $first: '$age' },
ageLast: { $last: '$age' }
}
}])
// 返回結果
{ "_id" : { "userAddr" : "HangZhou" }, "totalCount" : 3, "ageSum" : 90, "ageAvg" : 30, "ageMax" : 40, "ageMin" : 20, "ageFirst" : 30, "ageLast" : 40 }
{ "_id" : { "userAddr" : "BeiJing" }, "totalCount" : 1, "ageSum" : 30, "ageAvg" : 30, "ageMax" : 30, "ageMin" : 30, "ageFirst" : 30, "ageLast" : 30 }
{ "_id" : { "userAddr" : "ShenZhen" }, "totalCount" : 2, "ageSum" : 52, "ageAvg" : 26, "ageMax" : 27, "ageMin" : 25, "ageFirst" : 25, "ageLast" : 27 }
{ "_id" : { "userAddr" : "ShangHai" }, "totalCount" : 1, "ageSum" : 32, "ageAvg" : 32, "ageMax" : 32, "ageMin" : 32, "ageFirst" : 32, "ageLast" : 32 }
{ "_id" : { "userAddr" : "GuangZhou" }, "totalCount" : 3, "ageSum" : 68, "ageAvg" : 22.666666666666668, "ageMax" : 28, "ageMin" : 20, "ageFirst" : 28, "ageLast" : 20 }
>
// 指定組_id為null,計算集合中所有文件的總價格和平均數量以及計數:
db.getCollection("user").aggregate([{
$group: {
_id: null,
totalCount: { $sum: 1 },
ageSum: { $sum: '$age' },
ageAvg: { $avg: '$age' },
ageMax: { $max: '$age' },
ageMin: { $min: '$age' },
ageFirst: { $first: '$age' },
ageLast: { $last: '$age' }
}
}])
// 返回結果
{ "_id" : null, "totalCount" : 10, "ageSum" : 272, "ageAvg" : 27.2, "ageMax" : 40, "ageMin" : 20, "ageFirst" : 25, "ageLast" : 20 }
資料轉換:將集合中的資料按addr分組,然後把所有age轉換成陣列,ages可以自定義,是分組後的列表
使用示例:$push
db.getCollection("user").aggregate([{
$group: {
_id: { userAddr: '$addr' },
totalCount: { $sum: 1 },
ages: { $push: '$age' }
}
}])
// 返回結果
{ "_id" : { "userAddr" : "HangZhou" }, "totalCount" : 3, "ages" : [ 30, 20, 40 ] }
{ "_id" : { "userAddr" : "BeiJing" }, "totalCount" : 1, "ages" : [ 30 ] }
{ "_id" : { "userAddr" : "ShenZhen" }, "totalCount" : 2, "ages" : [ 25, 27 ] }
{ "_id" : { "userAddr" : "ShangHai" }, "totalCount" : 1, "ages" : [ 32 ] }
{ "_id" : { "userAddr" : "GuangZhou" }, "totalCount" : 3, "ages" : [ 28, 20, 20 ] }
// 用系統變數$$ROOT按addr對文件進行分組,生成的文件不得超過BSON文件大小限制。
// $$ROOT代表文件本身或者說文件所有欄位
db.getCollection("user").aggregate([{
$group: {
_id: { userAddr: '$addr' },
users: { $push: '$$ROOT' }
}
}])
// 返回結果
{ "_id" : { "userAddr" : "HangZhou" }, "users" : [ { "_id" : 6, "name" : "LiSi", "age" : 30, "addr" : "HangZhou" }, { "_id" : 7, "name" : "KaiFa", "age" : 20, "addr" : "HangZhou" }, { "_id" : 8, "name" : "QianDuan", "age" : 40, "addr" : "HangZhou" } ] }
{ "_id" : { "userAddr" : "BeiJing" }, "users" : [ { "_id" : 3, "name" : "LaoWan", "age" : 30, "addr" : "BeiJing" } ] }
{ "_id" : { "userAddr" : "ShenZhen" }, "users" : [ { "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }, { "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "ShenZhen" } ] }
{ "_id" : { "userAddr" : "ShangHai" }, "users" : [ { "_id" : 4, "name" : "WangWu", "age" : 32, "addr" : "ShangHai" } ] }
{ "_id" : { "userAddr" : "GuangZhou" }, "users" : [ { "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "GuangZhou" }, { "_id" : 9, "name" : "YunWei", "age" : 20, "addr" : "GuangZhou" }, { "_id" : 10, "name" : "CeSi", "age" : 20, "addr" : "GuangZhou" } ] }
$match + $group
使用示例:
// 單獨使用 $match
db.getCollection("user").aggregate([
{ $match : { age : { $gt: 20, $lt: 30} } }
])
{ "_id" : 1, "name" : "ZhangSan", "age" : 25, "addr" : "ShenZhen" }
{ "_id" : 2, "name" : "XiaoMing", "age" : 27, "addr" : "ShenZhen" }
{ "_id" : 5, "name" : "ZhaoSi", "age" : 28, "addr" : "GuangZhou" }
// 使用 $match + $group
db.getCollection("user").aggregate([
{ $match : { age : { $gt: 20, $lt: 30} } },
{
$group: {
_id: { userAddr: '$addr' },
totalCount: { $sum: 1 }
}
}
])
{ "_id" : { "userAddr" : "ShenZhen" }, "totalCount" : 2 }
{ "_id" : { "userAddr" : "GuangZhou" }, "totalCount" : 1 }
注意:$match 必須使用在 $group 之前
4、資料更新
- db.collection.update():更新或替換集合中符合條件的一個或多個文件;
- db.collection.updateOne():只更新集合中符合條件的第一個文件,即使有多個文件(版本3.2新增)
- db.collection.updateMany():更新集合中所有符合條件的文件(版本3.2新增)
- db.collection.replaceOne():替換除
_id
欄位以外的文件的所有內容
db.collection.update()
根據update
指定的表示式可以修改文件中符合條件的欄位或代替整個文件。具體的語法格式如下:
db.collection.update(
<query>, //查詢表示式
<update>, //更新表示式
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // 版本4.2新增
}
)
引數說明:
-
query:更新文件的查詢表示式;如果指定了引數
upsert: true
並且集合中沒有符合查詢條件的文件,查詢條件中有關於欄位_id
指定了.
分隔符的,並不會插入新的文件; -
update:主要包含三種格式
- 1.更新文件:只包含更新操作符表示式;
- 2.替換文件:只包含
<field1>: <value1>
對; - 3.聚合管道:版本4.2新增,詳細參考官方文件。
-
upsert:當query查詢條件沒符合更新的文件,就新建立文件(可選),預設值為false;
-
multi:是否更新多個符合條件的文件(可選),預設值為false,只更新符合條件的第一個文件;
-
writeConcern:參考**db.collection.insert()**相同引數說明;
-
collation:指定校對規則(可選,版本3.4新增);
-
arrayFilters:文件陣列更新過濾操作符(可選,版本3.6新增);
詳細參考:https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-array-update-operations
-
hint:採用文件或字串的形式指定適用於查詢表示式的索引,如果索引不存在則報錯(可選,版本4.2新增)。
使用示例:
使用示例將通過使用兩種場景進行,一是沒有使用引數選項upsert
,二是使用引數選項upsert
。
- 不使用選項upsert
// 測試資料
db.books.remove({});
db.books.insertMany([
{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : { "publisher" : "1111", "pages" : 430 },
"tags" : [ "technology", "computer" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
},
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : { "publisher" : "5555", "pages" : 150 },
"tags" : [ ],
"ratings" : [ { "by" : "xyz", "rating" : 5 } ],
"reorder" : false
}
]);
/* 使用選項引數 upsert: true
1、如果查詢表示式找到匹配的文件,則執行更新操作;
2、如果查詢表示式沒有找到匹配的文件,則執行插入操作;
*/
db.books.update(
{ item: "ZZZ135" }, // 查詢表示式
{ // 更新或替換文件
item: "ZZZ135",
stock: 5,
tags: [ "database" ]
},
{ upsert: true }
);
// 1.使用更新操作表示式
/* $set操作符
1、查詢表示式指定需要更新的文件 _id;
2、$inc操作符: stock的欄位值+5;
3、$set操作符: 替換item欄位值,替換嵌入文件info的publisher欄位值,替換tags欄位值,替換陣列ratings的第二個元素值
*/
db.books.update(
{ _id: 1 },
{
$inc: { stock: 5 },
$set: {
item: "ABC123",
"info.publisher": "2222",
tags: [ "software" ],
"ratings.1": { by: "xyz", rating: 3 }
}
}
);
更新之後的文件:
{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : { "publisher" : "2222", "pages" : 430 },
"tags" : [ "software" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : false
}
// 2.為已存在的陣列新增元素
// $push操作符: 為指定文件陣列ratings新增一個元素
db.books.update(
{ _id: 2 },
{
$push: { ratings: { "by" : "jkl", "rating" : 2 } }
}
);
更新之後的文件:
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : {
"publisher" : "5555",
"pages" : 150
},
"tags" : [ ],
"ratings" : [
{ "by" : "xyz", "rating" : 5 },
{ "by" : "jkl", "rating" : 2 }
],
"reorder" : false
}
// 3.文件移除欄位
// $unset操作符: 移除文件的指定欄位,為_id:1文件移除tags欄位
db.books.update( { _id: 1 }, { $unset: { tags: 1 } } );
更新後的文件:
{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : {
"publisher" : "1111",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
}
// 4.替換整個文件
// 替換_id:2的文件
db.books.update(
{ _id: 2 },
{
item: "XYZ123",
stock: 10,
info: { publisher: "2255", pages: 150 },
tags: [ "baking", "cooking" ]
}
);
更新後的文件:
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 10,
"info" : { "publisher" : "2255", "pages" : 150 },
"tags" : [ "baking", "cooking" ]
}
// 5.更新多個文件
db.books.update(
{ stock: { $lte: 10 } },
{ $set: { reorder: true } },
{ multi: true }
);
更新後的全部文件:
[
{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : {
"publisher" : "2222",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : true
}
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 10,
"info" : { "publisher" : "2255", "pages" : 150 },
"tags" : [ "baking", "cooking" ],
"reorder" : true
}
]
- 使用upserts選項
/* 使用選項引數 upsert: true
1、如果查詢表示式找到匹配的文件,則執行更新操作;
2、如果查詢表示式沒有找到匹配的文件,則執行插入操作;
*/
// 1.插入未符合更新條件的文件
db.books.update(
{ item: "ZZZ135" },
{
item: "ZZZ135",
stock: 5,
tags: [ "database" ]
},
{ upsert: true }
);
因為集合並未滿足條件的文件,則插入的文件為:
{
"_id" : ObjectId("5da78973835b2f1c75347a83"),
"item" : "ZZZ135",
"stock" : 5,
"tags" : [ "database" ]
}
// 2.插入未符合更新條件並且基於更新操作符的文件
// 如果沒有符合更新查詢條件,並且使用的是更新操作符,則會基於當前的查詢條件和更新操作符欄位插入新的文件
db.books.update(
{ item: "BLP921" },
{
$set: { reorder: false },
$setOnInsert: { stock: 10 }
},
{ upsert: true }
);
新插入的文件為:
{
"_id" : ObjectId("5da79019835b2f1c75348a0a"),
"item" : "BLP921",
"reorder" : false,
"stock" : 10
}
// 3.插入未符合更新條件並且基於聚合管道的文件
// 關於聚合管道請參考官方文件:https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline
// 4.插入未符合更新條件並且同時聯合多文件操作符的文件
如果不符合查詢條件,則只會插入單個文件
db.books.update(
{ "info.publisher": "Self-Published" },
{
$set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 }
},
{ upsert: true, multi: true }
);
新插入的文件:
{
"_id" : ObjectId("5db337934f670d584b6ca8e0"),
"info" : { "publisher" : "Self-Published" },
"reorder" : false,
"stock" : 25,
"tags" : [ "literature", "hardcover" ]
}
db.collection.updateOne() 與 db.collection.updateMany()
根據update
指定的引數可以修改文件中符合條件的欄位或代替整個文件,與**db.collection.update()**不同的是每次只更新單個文件。
根據update
指定的引數可以修改文件中符合條件的欄位或代替整個文件,與**db.collection.updateOne()**不同的是更新所有符合條件的文件。
語法格式如下:
// 更新單個文件語法:
db.collection.updateOne(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string>
}
)
// 更新單個或多個文件語法:
db.collection.updateMany(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string>
}
)
引數說明:參考**db.collection.update()**的引數說明。
使用示例:
// 參考db.collection.update()
db.collection.replaceOne( filter , replacement , options )
db.collection.replaceOne(
<filter>,
<replacement>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>
}
)
引數說明:參考**db.collection.update()**的引數說明。
使用示例:
// 使用一個新的文件來替換name為B的文件
db.user.replaceOne(
{ name: "B" },
{ name: "newB", age: 8, addr: "GuangZhou"}
)
5、資料刪除
- db.collection.deleteOne():只刪除集合中符合條件的一個文件
- db.collection.deleteMany():刪除集合中所有符合條件的文件
- db.collection.remove():刪除集合中符合條件的一個或多個文件(
已廢棄)
db.collection.deleteOne() 與 db.collection.deleteMany()
根據filter
選項條件刪除集合中的單個或多個文件,具體語法格式如下:
// 刪除單個語法
db.collection.deleteOne(
<filter>,
{
writeConcern: <document>,
collation: <document>
}
)
// 刪除單個或者多個語法
db.collection.deleteMany(
<filter>,
{
writeConcern: <document>,
collation: <document>
}
)
引數說明:
- filter:指定基於查詢表示式的過濾條件,關於查詢表示式可以檢視
db.collecion.find()
中的<query>
; - writeConcern:寫入策略,預設為 1,即要求確認寫操作,0 是不要求。
- collation:指定校對規則(可選,版本3.4新增);
使用示例:
// 刪除指定條件的單個文件
db.user.deleteOne( { "_id" : 1 } );
{ "acknowledged" : true, "deletedCount" : 1 }
// 刪除指定條件的多個文件
db.user.deleteMany( {"addr" : "GuangZhou"} );
{ "acknowledged" : true, "deletedCount" : 2 }
db.collection.remove()
根據filter
選項條件刪除集合中的單個或多個文件,具體語法格式如下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
引數說明:
- query:必選項,是設定刪除的文件的條件。
- justOne:布林型的可選項,預設為false,刪除符合條件的所有文件,如果設為 true,則只刪除一個文件。
- writeConcem:可選項,設定丟擲異常的級別。
使用示例:
// remove 刪除全部
db.day.remove({})
// remove 條件刪除
db.day.remove({age:10})
注意:
此方法已經過時,官方推薦使用deleteOne和deleteMany函式來實現刪除操作。且remove()函式並不會真正的釋放掉儲存空間,需要刪除後,再用管理員許可權的賬戶執行db.repairDatabase()函式來釋放儲存空間!
索引操作
1、建立索引
- db.collection.createIndex(keys, options):建立集合索引
引數說明:
keys:物件引數為1表示正序建立索引,-1表示逆序建立索引。如果新增多個屬性為聯合索引
options:可選屬性如下:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引過程會阻塞其它資料庫操作,background可指定以後臺方式建立索引,即增加 “background” 可選引數。 “background” 預設值為false。 |
unique | Boolean | 建立的索引是否唯一。指定為true建立唯一索引。預設值為false. |
name | string | 索引的名稱。如果未指定,MongoDB的通過連線索引的欄位名和排序順序生成一個索引名稱。 |
dropDups | Boolean | **3.0+版本已廢棄。**在建立唯一索引時是否刪除重複記錄,指定 true 建立唯一索引。預設值為 false. |
sparse | Boolean | 對文件中不存在的欄位資料不啟用索引;這個引數需要特別注意,如果設定為true的話,在索引欄位中不會查詢出不包含對應欄位的文件.。預設值為 false. |
expireAfterSeconds | integer | 指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間。 |
v | index version | 索引的版本號。預設的索引版本取決於mongod建立索引時執行的版本。 |
weights | document | 索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其他索引欄位的得分權重。 |
default_language | string | 對於文字索引,該引數決定了停用詞及詞幹和詞器的規則的列表。 預設為英語 |
language_override | string | 對於文字索引,該引數指定了包含在文件中的欄位名,語言覆蓋預設的language,預設值為 language. |
使用示例:
// 唯一索引
> db.user.createIndex({name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
// 複合索引
> db.user.createIndex({name:1, addr:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
2、檢視索引
- db.collection.getIndexes():檢視集合索引
- db.collection.totalIndexSize():檢視集合索引大小
// 檢視user集合索引大小
> db.user.totalIndexSize()
61440
// 檢視user集合索引
> db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_"
},
{
"v" : 2,
"key" : {
"name" : 1,
"addr" : 1
},
"name" : "name_1_addr_1"
},
{
"v" : 2,
"key" : {
"name" : 1
},
"name" : "name_1"
}
]
3、刪除索引
-
db.collection.dropIndexes():刪除集合所有索引(除了_id欄位外)
-
db.collection.dropIndex({‘索引名稱’}):刪除集合指定索引(升序降序不能錯)
// 刪除所有索引,只會刪除除了_id以外的所有索引
> db.user.dropIndexes()
{
"nIndexesWas" : 3,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
// 刪除name欄位的索引,升序降序不能錯,如果為-1,則提示無索引
> db.user.dropIndex({name:1})
{ "nIndexesWas" : 3, "ok" : 1 }
4、定時刪除任務
利用 TTL 集合對儲存的資料進行失效時間設定:經過指定的時間段後或在指定的時間點過期,MongoDB 獨立執行緒去清除資料。
在指定秒數後使文件過期
1、首先建立索引,設定過期時間為180秒
db.col.createIndex( { createDate: 1 }, { expireAfterSeconds: 180 } )
2、然後儲存資料入庫
db.col.insert( { _id: 1, createDate: new Date() } )
3、mongodb 會在大於 expireAfterSeconds 指定值的秒數後,過期
在特定時鐘時間使文件過期
1、首先建立索引,設定 expireAfterSeconds 為 0
db.col.createIndex( { createDate: 1 }, { expireAfterSeconds: 0 } )
2、然後儲存資料入庫
db.col.insert( { _id: 1, "createDate": new Date('July 22, 2020 12:00:00') } )
3、createDate 的值為特定的時間值,等時間到達expireAt的值時,這個文件就 失效了。
其他注意事項:
- 索引關鍵欄位必須是 Date 型別。
- 非立即執行:掃描 Document 過期資料並刪除是獨立執行緒執行,預設 60s 掃描一次,刪除也不一定是立即刪除成功。
- 單欄位索引,混合索引不支援
**參考:**https://www.cnblogs.com/jiangqw/p/12174746.html
備份恢復及匯入匯出
MongoDB 4.4版本 之後 MongoDB資料庫工具現在與MongoDB服務 分開發布 需要單獨安裝
- 下載地址:https://docs.mongodb.com/database-tools/
- 下載安裝或解壓,配置到環境變數 path 中,然後可以使用 mongodump、 mongorestore、 mongoimport、 mongoexport 命令
- 在匯入其他人的庫後,應該清空 -->該庫下的使用者 -->再建立使用者後再連線
資料匯出與匯入:mongoexport、mongoimport
1、匯出:mongoexport
1、概念:
mongoDB 中的 mongoexport 工具可以把一個 collection(集合) 匯出成JSON格式或CSV格式的檔案。可以通過引數指定匯出的資料項,也可以根據指定的條件匯出資料。
2、語法:
mongoexport -d dbname -c cname -o file --type json/csv -f field
引數說明:
-
-d、–db:資料庫名
-
-c 、–collection:集合名
-
-o、–out :輸出的檔名
-
–type: 輸出的格式,預設為json。可以為json/csv
-
-f:輸出的欄位,如果-type為csv,則需要加上-f “欄位名”
-
-h:指明資料庫宿主機的IP。如是本機可以去除該引數
-
-u:指明資料庫的使用者名稱
-
-p:指明資料庫的密碼
示例:
# 匯出dbname資料庫的cname集合中所有 _id,user_id,user_name,age,status 欄位到 /mongoBack/cname.json檔案中
mongoexport -d dbname -c cname -o /mongoBack/cname.json -f "_id,user_id,user_name,age,status"
2、匯入:mongoimport
當要插入的資料太多時,一條一條的insert在繁瑣了。所以,我們可以在程式碼編輯器中以JSON格式編輯好要插入的資料,以 *.json 檔案格式儲存,然後匯入資料庫:下面就是將mydata.json檔案,匯入到test資料庫的student集合中。
1、語法:
mongoimport -d dbname -c cname --file filename --headerline -f field
引數說明:
-
-d :資料庫名
-
-c :collection名
-
–type :匯入的格式預設json。可以為json/csv
-
-f :匯入的欄位名
-
–headerline :如果匯入的格式是csv,則可以使用第一行的標題作為匯入的欄位
-
–file :要匯入的檔案
-
–drop:匯入前把集合中的資料清空
-
-h:指明資料庫宿主機的IP。如是本機可以去除該引數
-
-u:指明資料庫的使用者名稱
-
-p:指明資料庫的密碼
示例:
# 把/mongoBack/cname.json中的資料匯入dbname資料中的cname集合中,並且只匯入_id,user_id,user_name,age,status欄位
mongoimport -d dbname -c cname --file /mongoBack/cname.json -f "_id,user_id,user_name,age,status" --drop
MongoDB備份與恢復:mongodump、mongorestore
3、備份:mongodump
1、語法:
mongodump -h host -u user -d dname -o dbdirectory
引數說明:
-
-d: 需要備份的資料庫例項,例如:test
-
-o: 備份的資料存放位置,該路徑需要提前建立。例:/home/mongodump/
-
-h:指明資料庫宿主機的IP。如是本機可以去除該引數
-
-u:指明資料庫的使用者名稱
-
-p:指明資料庫的密碼
-
–port:埠號。如是預設可以去除該引數
示例:
# 備份單個表
mongodump -u user -p 123 --authenticationDatabase admin -d dname -c cname -o /backup/mongodb/dname_d_bak_201507021701.bak
# 備份單個庫
mongodump -u user -p 123 --authenticationDatabase admin -d dname -o /backup/mongodb/
# 備份所有庫
mongodump -u user -p 123 --authenticationDatabase admin -o /backup/allbak
# 備份所有庫推薦使用新增--oplog引數的命令,這樣的備份是基於某一時間點的快照,只能用於備份全部庫時才可用,單庫和單表不適用:
mongodump -h 127.0.0.1 --port 27017 --oplog -o /backup/allbak
4、恢復:mongorestore
1、語法:
mongorestore -h host -u user -d dname --dir dbdirectory
引數或名:
-
-d: 需要恢復的資料庫例項,當然這個名稱也可以和備份時候的不一樣,比如test2
-
–dir: 備份資料所在位置,例如:/home/mongodump/itcast/
-
–drop: 恢復前把集合中的資料清空。
-
-h: MongoDB所在伺服器地址。如是本機可以去除該引數
-
-u:指明資料庫的使用者名稱
-
-p:指明資料庫的密碼
-
–port:埠號。如是預設可以去除該引數
示例:
# 恢復單表
mongorestore -u user -p 123 --authenticationDatabase admin -d dname -c cname /backup/mongodb/dname_d_bak_201507021701.bak/myTest/d.bson
# 恢復單個庫:
mongorestore -u user -p 123 --authenticationDatabase admin -d dname /backup/mongodb/
# 恢復所有庫:
mongorestore -u user -p 123 --authenticationDatabase admin /backup/allbak
# 備份時如果加了--oplogReplay引數,恢復時也要加上--oplogReplay引數,具體命令如下(下面是恢復單庫的命令):
mongorestore -d dname --oplogReplay /home/mongo/swrdbak/swrd/
注意:
1、mongorestore恢復資料預設是追加,如打算先刪除後匯入,可以加上–drop引數,不過新增–drop引數後,會將資料庫資料清空後再匯入,如果資料庫備份後又新加入了資料,也會將新加的資料刪除,它不像mysql有一個存在的判斷
2、mongodump在mongo關閉時,也是可以備份的,不過需要指定資料目錄,命令為:mongodump --dbpath /data/db
使用MongoDB其他命令列工具遠端操作連線時,儘量加上如下引數.
--authenticationDatabase admin
Java操作MongoDB
參考:http://c.biancheng.net/view/6571.html
SpringBoot整合MongoDB
Spring Boo與MongoDB整合,並通過MongoRepository以及MongoTemplate來執行CRUD操作。
1、準備工作
1.1、依賴包版本號:
Spring Boot:2.3.0.RELEASE
Spring Boot Data MongoDB:2.3.0.RELEASE
MongoDB:4.2.6
MongoDB Driver:4.0.3
1.2、要操作集合資料結構(即model)
Department:
欄位名 | 型別 |
---|---|
id | String |
name | String |
description | String |
employees | Arrays |
Employee:
欄位名 | 型別 |
---|---|
empId | String |
name | String |
age | int |
address | String |
2、建立專案
2.1、建立SpringBoot專案,並新增依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.2、配置檔案增加MongoDB配置,application.properties
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.database=test
spring.data.mongodb.username=admin
spring.data.mongodb.password=password
# 簡寫,其中name是使用者名稱,pwd是密碼,test是資料庫
# spring.data.mongodb.uri=mongodb://127.0.0.1:27017/test
# spring.data.mongodb.uri=mongodb://name:pwd@127.0.0.1:27017/test
# 如果要配置多個資料庫,則中間用","分割
# spring.data.mongodb.uri=mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/test
備註:username不能是admin管理員使用者。必須是當前database的使用者才可以
2.3、測試專案能否正常啟動,然後檢視專案結構:
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─example
│ │ │ └─mongodb
│ │ │ │ MongodbApplication.java
│ │ │ │
│ │ │ ├─controller
│ │ │ │ DepartmentController.java
│ │ │ │ EmployeeController.java
│ │ │ │
│ │ │ ├─model
│ │ │ │ Department.java
│ │ │ │ Employee.java
│ │ │ │
│ │ │ └─repository
│ │ │ DeptRepository.java
│ │ │ DeptTemplate.java
│ │ │ EmpRepository.java
│ │ │ EmpTemplate.java
│ │ │
│ │ └─resources
│ │ │ application.properties
│ │ │
│ │ ├─static
│ │ └─templates
│ └─test
│
└─target
2.4、建立Model Bean(Department.class、Employee.clss)
package com.example.mongodb.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import java.io.Serializable;
import java.util.List;
@Data
@Document("Department")
public class Department implements Serializable {
@Id
private String id;
@Indexed(name = "deptName")
private String name;
private String description;
@DBRef
private List<Employee> employees;
}
package com.example.mongodb.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.io.Serializable;
@Data
@Document("Employee")
public class Employee implements Serializable {
@Id
private String empId;
private String name;
private int age;
private String address;
}
2.5、兩種運算元據的方式:MongoRepository、MongoTemplate
MongoRepository
DeptRepository.class、EmpRepository.class
package com.example.mongodb.repository;
import com.example.mongodb.model.Department;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface DeptRepository extends MongoRepository<Department,String> {
@Query(value = "{'Employee.name': ?0}", fields = "{'employees' : 0}")
Department findDepartmentByEmployeeName(String empName);
List<Department> findDepartmentByName(String name);
}
package com.example.mongodb.repository;
import com.example.mongodb.model.Employee;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface EmpRepository extends MongoRepository<Employee,String> {
}
MongoTemplate
DeptTemplate.class、EmpTemplate.class
package com.example.mongodb.repository;
import com.example.mongodb.model.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class DeptTemplate {
@Autowired
private MongoTemplate mongoTemplate;
public List<Department> findAll() {
return mongoTemplate.findAll(Department.class);
}
public List<Department> findDepartmentByName(String deptName){
Query query = new Query();
query.addCriteria(Criteria.where("name").is(deptName));
return mongoTemplate.find(query, Department.class);
}
public Department save(Department department) {
mongoTemplate.save(department);
return department;
}
public Department update(Department department){
Query query = new Query();
query.addCriteria(Criteria.where("id").is(department.getId()));
Update update = new Update();
update.set("name", department.getName());
update.set("description", department.getDescription());
return mongoTemplate.findAndModify(query, update, Department.class);
}
public void deleteById(String deptId) {
Query query = new Query();
query.addCriteria(Criteria.where("id").is(deptId));
mongoTemplate.remove(query, Department.class);
}
}
package com.example.mongodb.repository;
import com.example.mongodb.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class EmpTemplate {
@Autowired
private MongoTemplate mongoTemplate;
public List<Employee> findAll() {
return mongoTemplate.findAll(Employee.class);
}
public Employee save(Employee employee) {
mongoTemplate.save(employee);
return employee;
}
public Employee update(Employee employee){
Query query = new Query();
query.addCriteria(Criteria.where("empId").is(employee.getEmpId()));
Update update = new Update();
update.set("name", employee.getName());
update.set("description", employee.getAddress());
return mongoTemplate.findAndModify(query, update, Employee.class);
}
public void deleteById(String empId) {
Query query = new Query();
query.addCriteria(Criteria.where("empId").is(empId));
mongoTemplate.remove(query, Employee.class);
}
}
2.6、建立Controller(DepartmentController.class、EmployeeController.class)
package com.example.mongodb.controller;
import com.example.mongodb.model.Department;
import com.example.mongodb.model.Employee;
import com.example.mongodb.repository.DeptRepository;
import com.example.mongodb.repository.DeptTemplate;
import com.example.mongodb.repository.EmpRepository;
import com.example.mongodb.repository.EmpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@RestController
public class DepartmentController {
// v1的介面使用 MongoRepository 方式運算元據
@Autowired DeptRepository deptRepository;
@Autowired EmpRepository empRepository;
// v2的介面使用 MonoTemplate 方式運算元據
@Autowired DeptTemplate deptTemplate;
@Autowired EmpTemplate empTemplate;
/********************* MongoRepository方式 *********************/
@PostMapping("/v1/dept/save")
public Department v1save(@RequestBody Department department) {
// 新增部門資訊前首先儲存員工資訊
List<Employee> employees = Optional.ofNullable(department.getEmployees()).orElse(Collections.emptyList());
employees.forEach(employee -> empRepository.save(employee));
return deptRepository.save(department);
}
@GetMapping("/v1/dept/list")
public List<Department> v1list(){
return deptRepository.findAll();
}
@PutMapping("/v1/dept/update/{deptId}")
public Department v1update(@RequestBody Department department, @PathVariable String deptId) {
department.setId(deptId);
List<Employee> employees = Optional.ofNullable(department.getEmployees()).orElse(Collections.emptyList());
employees.forEach(Employee -> empRepository.save(Employee));
return deptRepository.save(department);
}
@DeleteMapping("/v1/dept/delete/{deptId}")
public String v1delete(@PathVariable String deptId) {
deptRepository.deleteById(deptId);
return deptId;
}
@GetMapping("/v1/dept/get/{deptName}")
public List<Department> v1getByName(@PathVariable String deptName) {
return deptRepository.findDepartmentByName(deptName);
}
@GetMapping("/v1/dept/get/emp/{empName}")
public Department v1getByEmpName(@PathVariable String empName) {
return deptRepository.findDepartmentByEmployeeName(empName);
}
/********************* MonoTemplate方式 *********************/
@PostMapping("/v2/dept/save")
public Department v2save(Department department) {
List<Employee> employees = Optional.ofNullable(department.getEmployees()).orElse(Collections.emptyList());
employees.forEach(Employee -> empRepository.save(Employee));
return deptTemplate.save(department);
}
@GetMapping("/v2/dept/list")
public List<Department> v2list() {
return deptTemplate.findAll();
}
@PutMapping("/v2/dept/update")
public Department v2update(Department department){
List<Employee> employees = Optional.ofNullable(department.getEmployees()).orElse(Collections.emptyList());
employees.forEach(emp -> empRepository.save(emp));
return deptTemplate.update(department);
}
@DeleteMapping("/v2/dept/delete/{deptId}")
public void v2delete(@PathVariable String deptId) {
deptTemplate.deleteById(deptId);
}
@GetMapping("/v2/dept/get/{deptName}")
public List<Department> v2getByName(@PathVariable String deptName){
return deptTemplate.findDepartmentByName(deptName);
}
}
package com.example.mongodb.controller;
import com.example.mongodb.model.Department;
import com.example.mongodb.model.Employee;
import com.example.mongodb.repository.DeptRepository;
import com.example.mongodb.repository.DeptTemplate;
import com.example.mongodb.repository.EmpRepository;
import com.example.mongodb.repository.EmpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@RestController
public class EmployeeController {
// v1的介面使用 MongoRepository 方式運算元據,v2的介面使用 MonoTemplate 方式運算元據
@Autowired EmpRepository empRepository;
@Autowired EmpTemplate empTemplate;
/********************* MongoRepository方式 *********************/
@PostMapping("/v1/emp/save")
public Employee v1save(@RequestBody Employee employee) {
return empRepository.save(employee);
}
@GetMapping("/v1/emp/list")
public List<Employee> v1list(){
return empRepository.findAll();
}
@PutMapping("/v1/emp/update/{empId}")
public Employee v1update(@RequestBody Employee employee, @PathVariable String empId) {
//employee.setEmpId(empId);
return empRepository.save(employee);
}
@DeleteMapping("/v1/emp/delete/{empId}")
public String v1delete(@PathVariable String empId) {
empRepository.deleteById(empId);
return empId;
}
}
3、測試介面
v1的介面使用MongoRepository方式運算元據,v2的介面使用MonoTemplate方式運算元據。
###新增
POST http://localhost:8080/v1/dept/save
Content-Type: application/json
{
"id": "007",
"name": "阿里巴巴",
"description": "阿里巴巴Java開發",
"employees": [{
"empId": "1",
"name": "Sam Liu",
"age": 28,
"address": "深圳"
}]
}
###更新
PUT http://localhost:8080/v1/dept/update/007
Content-Type: application/json
{
"id": "007",
"name": "阿里巴巴-new",
"description": "阿里巴巴Web開發",
"employees": [
{
"empId": "1",
"name": "Sam Liu",
"age": 28,
"address": "深圳"
},
{
"empId": "2",
"name": "Tom",
"age": 38,
"address": "杭州"
}
]
}
###刪除
DELETE http://localhost:8080/v1/dept/delete/007
###查詢
GET http://localhost:8080/v1/dept/list
##############################################################
###新增
POST http://localhost:8080/v1/emp/save
Content-Type: application/json
{
"empId": "1",
"name": "Sam Liu",
"age": 28,
"address": "深圳"
}
###更新
PUT http://localhost:8080/v1/emp/update/1
Content-Type: application/json
{
"empId": "1",
"name": "Sam Liu-update",
"age": 28,
"address": "深圳-update"
}
###刪除
DELETE http://localhost:8080/v1/emp/delete/007
###查詢
GET http://localhost:8080/v1/emp/list
相關文章
- Redis 從入門到實戰Redis
- Locust 從入門到實戰
- Dubbo 一篇文章就夠了:從入門到實戰
- MongoDB從入門到刪庫MongoDB
- Docker從入門到實戰pdfDocker
- Docker實戰-從入門到跑路Docker
- Uni-app從入門到實戰APP
- MongoDB從入門到實戰之.NET Core使用MongoDB開發ToDoList系統(2)-Swagger框架整合MongoDBSwagger框架
- 小程式從入門到實戰系列(一)
- iOS逆向安防從入門到實戰iOS
- Angularjs 從入門到實戰(含專案教程)AngularJS
- go從入門到實戰-極客時間Go
- Spring Cloud 純乾貨,從入門到實戰SpringCloud
- Docker 實戰教程之從入門到提高 (八)Docker
- Docker 實戰教程之從入門到提高(三)Docker
- Docker 實戰教程之從入門到提高 (四)Docker
- Docker 實戰教程之從入門到提高(二)Docker
- Docker 實戰教程之從入門到提高(一)Docker
- Docker 實戰教程之從入門到提高 (七)Docker
- Docker 實戰教程之從入門到提高 (五)Docker
- Docker 實戰教程之從入門到提高 (六)Docker
- MongoDB從入門到實戰之.NET Core使用MongoDB開發ToDoList系統(1)-後端專案框架搭建MongoDB後端框架
- Linux入門到實戰Linux
- GraphQL搭配MongoDB入門專案實戰MongoDB
- MongoDB從入門到實戰之.NET Core使用MongoDB開發ToDoList系統(3)-系統資料集合設計MongoDB
- JVM 從入門到實戰--- 01 JVM 基本介紹JVM
- web3從入門到實戰-理論篇Web
- Python實戰案例彙總,帶你輕鬆從入門到實戰Python
- Gin + GORM 入門到實戰GoORM
- GraphQL 從入門到實踐
- Hadoop大資料探勘從入門到進階實戰Hadoop大資料
- Spring Boot從入門到實戰(十):非同步處理Spring Boot非同步
- web3從入門到實戰-NFT與代幣Web
- 前端大資料視覺化從入門到實戰前端大資料視覺化
- scala 從入門到入門+
- makefile從入門到入門
- Python專案實戰(一)《Python程式設計 從入門到實踐》Python程式設計
- JVM 從入門到實戰 | 03 簡述垃圾回收演算法JVM演算法