一篇文章解決MongoDB的所有問題
阿新 • • 發佈:2020-05-09
[TOC]
# 一、MongoDB相關概念
## 1.1 業務應用場景
```
傳統的關係型資料庫(如MySQL)。在數作的"三高"需求以及應對Web.0的網站需求面前,顯得力不從心。
解釋:三高“需求:
·High performance-高併發
·Huge Storage-海量資料
·High Scalability&&High Availability-高擴充套件性和高可用性的需求
```
### 1.1.1 而MongoDB可應對“三高"需求·
```
具體的應用場景:
1)社交場景,使MongoDB存存使用者資訊,以及使用者發表的朋友圈資訊,通過地理位置索引實現跗近的人、地點等功能。
2〕遊戲場景,使用MongoDB儲存遊戲使用者資訊,使用者的裝備、積分等直接以內嵌文件的形式儲存,方便查詢、高效率儲存和訪問。
3〕物流場景。使用MongoDB儲存訂單資訊,訂單狀態在運送過程中會不斷更新,以MongoDB內嵌陣列的形式來儲存,一次查詢就能將訂單所有的變更讀取出來。
4〕物聯網場景,使用MongoDB儲存所有接入的智慧裝置資訊,以及裝置彙報的日誌資訊,對這些資訊講行多維度的分析·
5)視訊直播,使用MongoDB存使用者資訊、點贊互動資訊等。
```
使用MongoDB共同特點:
```
1.資料量大
2.寫入操作頻繁
3.價值較低的資料,對事務性要求不高
```
### 1.1.2 什麼時候選擇MongoDB?
```
在架構選型上,除了上述的三個特點外,如果你還猶是否要選擇它?可以考慮以下的一些問題:
應用不需要事務及複雜join支援
新應用,需求會變,資料模型無法確定。想快速迭代開發
應需要2000-3000以上的讀寫QPS(更高也可以)
應用需要TB至PB級別數儲存
應甲發展迅速,需要能快速水平擴充套件
應甲要求存的數庭不丟失
應需要的99%高可用
應用需要大量的地理位置查詢、文字查詢
如果上述有1個符合,可以考慮MongoDB,2個及以上符合,選懌MongoDB絕不會後悔.
```
### 1.1.3 如果用mysql?
```
相對於mysql,MongoDB可以耕地的成本解決問題(包括學習,開發,運維等成本)
```
### 1.1.4MongoDB的特點
```
1.高效能:索引支援更快的查詢,減少了資料庫系統上的IO活動
2.高可用性:複製工具成為副本集,它可提供自動故障轉移和資料冗餘
3.高擴充套件性:水平擴充套件性
4.豐富的查詢支援:支援讀寫,資料聚合,文字搜尋和地理空間查詢
5.其他特點:如無模式(動態模式)、靈活的文件模型
```
# 二、MongoDB簡介
```
MongoDB是一個開源、高效能、無模式的文件型資料庫。當初的設計就是用於簡化開發和方便擴充套件,是nosql(非關係性)資料庫產品中的一種。是最像關係型資料庫(MySQL)的非關係型資料庫。
它支援的數結構非常鬆散,是一種類似於JSON的格式叫BSON,所以它既可以儲存比較複雜的數庭型別,又相當的靈活.
MongoDB中的記錄是一個文件,它是一個由欄位和值對(field:value)組成的資料結構。MongoDB文件類似於JSON物件,即一個文件認為就是一個物件。欄位的資料型別是字元型,它的值除了便用基本的一些型別外,還可以包括其他文件、普通陣列和文件陣列
```
# 三、體系結構
Mysql和MongoDB對比
![](https://gitee.com/guyouyin/image/raw/master/img/20200506234449.png)
![](https://gitee.com/guyouyin/image/raw/master/img/20200506234542.png)
![](https://gitee.com/guyouyin/image/raw/master/img/20200506234918.png)
## 3.1 資料模型
```
MongoDB的小儲存單位就是文件(document)物件。文件(document)物件對應於關係型資料庫的行。資料在MongoDB中以 BSON(Binary-JSON)文件的格式儲存在磁碟上。
BSON(Binary Serialized Document Format)是一種類json的一種二進位制形式的儲存格式,簡稱Binary JSON。BSON和JSON一樣,支援 內嵌的文件物件和陣列物件,但是BSON有JSON沒有的一些資料型別,如Date和BinData型別。 BSON採用了類似於 C 語言結構體的名稱、對錶示方法,支援內嵌的文件物件和陣列物件,具有輕量性、可遍歷性、高效性的三個特點,可 以有效描述非結構化資料和結構化資料。這種格式的優點是靈活性高,但它的缺點是空間利用率不是很理想。
Bson中,除了基本的JSON型別:string,integer,boolean,double,null,array和object,mongo還使用了特殊的資料型別。這些型別包括 date,object id,binary data,regular expression 和code。每一個驅動都以特定語言的方式實現了這些型別,檢視你的驅動的文件來獲取詳 細資訊。
```
BSON資料型別參考列表:
| 資料型別 | 描述 | 舉例 |
| ---------- | ------------------------------------------------------------ | ----------------------------------------------------- |
| 字串 | UTF-8字串都可表示為字串型別的資料 | {"x" : "foobar"} |
| 物件id | 物件id是文件的12位元組的唯一 ID | {"X" :ObjectId() } |
| 布林值 | 真或者假:true或者false | {"x":true}+ |
| 陣列 | 值的集合或者列表可以表示成陣列 | {"x" : ["a", "b", "c"]} |
| 32位整數 | 型別不可用。JavaScript僅支援64位浮點數,所以32位整數會被 自動轉換。 | shell是不支援該型別的,shell中預設會轉換成64 位浮點數 |
| 64位整數 | 不支援這個型別。shell會使用一個特殊的內嵌文件來顯示64位 整數 | shell是不支援該型別的,shell中預設會轉換成64 位浮點數 |
| 64位浮點數 | shell中的數字就是這一種型別 | {"x":3.14159,"y":3} |
| null | 表示空值或者未定義的物件 | {"x":null} |
| undefined | 文件中也可以使用未定義型別 | {"x":undefined} |
| 符號 | shell不支援,shell會將資料庫中的符號型別的資料自動轉換成字串 | |
| 正則表示式 | 文件中可以包含正則表示式,採用JavaScript的正則表示式語法 | {"x" : /foobar/i} |
| 程式碼 | 文件中還可以包含JavaScript程式碼 | {"x" : function() { /* …… */ }} |
| 二進位制資料 | 二進位制資料可以由任意位元組的串組成,不過shell中無法使用 | |
| 大值/ 小值 | BSON包括一個特殊型別,表示可能的大值。shell中沒有這個 型別。 | |
# 四、官網下載
```
https://www.mongodb.com/download-center/community
```
![](https://gitee.com/guyouyin/image/raw/master/img/20200507000013.png)
```
據上圖所示下zip包。
提示:版朩的選擇:
MongoDB的版本命名規範如:x.y.z
y為奇數時表示當前版朩為開發版:1.5.2、4.1.13
y為偶數時表示當前版朩為穩定版,如:1.6.3、4.0.10
z是修正板本號,數字越大越好。
```
# 五、啟動方式
## 5.1 命令啟動
```
第一步:在bin的同級目錄新建data目錄,在data目錄中新建db子目錄。作為存放資料庫檔案的位置
第二步:cmd進入bin目錄中,敲:mongod --dbpath=..\data\db 出現以下圖代表成功
```
![](https://gitee.com/guyouyin/image/raw/master/img/20200507001556.png)
## 5.2 製作系統服務
```
前提準備:
(1):log\mongod.log建立存日誌的檔案
(2):E:\mongodb\data\db 建立存資料的資料夾
(3):把bin目錄配置為環境變數,敲mongo命令登入連線
將啟動命令,製作為系統服務(開機自啟):
mongod --bind_ip 0.0.0.0 --port 27017 --logpath E:\mongodb\log\mongod.log --logappend --dbpath E:\mongodb\data\db --serviceName "MongoDB" --serviceDisplayName "MongoDB" --install
```
## 5.3 配置檔案啟動
```
第一步:在bin的同級目錄新建conf目錄,在data目錄中新建mongod.cfg檔案
第二步:在mongod.conf中寫:dbPath是上面新建存放資料庫檔案的位置
storage:
dbPath: E:\mongodb\data\db
第三步:啟動方式(cmd當前在bin目錄下)
mongod -f ..\conf\mongod.cfg
或
mongod --config "E:\mongodb\conf\mongod.cfg"
```
```
詳細配置項內容可以參考官方文件:https://docs.mongodb.com/manual/reference/configuration-options/
```
【注意】
1)配置檔案中如果使用雙引號,比如路徑地址,自動會將雙引號的內容轉義。如果不轉義,則會報錯:
```
error-parsing-yaml-config-file-yaml-cpp-error-at-line-3-column-15-unknown-escape-character-d
```
解決:
a. 對 \ 換成 / 或 \\
b. 如果路徑中沒有空格,則無需加引號。 2)配置檔案中不能以Tab分割欄位
mongod --dbpath=..\data\db
storage: #The directory where the mongod instance stores its data.Default Value is "\data\db" on Windows. dbPath: D:\02_Server\DBServer\mongodb-win32-x86_64-2008plus-ssl-4.0.1\data
error-parsing-yaml-config-file-yaml-cpp-error-at-line-3-column-15-unknown-escape-character-d
解決:
將其轉換成空格。
**更多引數配置:**
```
systemLog:
destination: file
#The path of the log file to which mongod or mongos should send all diagnostic logging information
path: "D:/02_Server/DBServer/mongodb-win32-x86_64-2008plus-ssl-4.0.1/log/mongod.log" logAppend: true storage:
journal:
enabled: true #The directory where the mongod instance stores its data.Default Value is "/data/db".
dbPath: "D:/02_Server/DBServer/mongodb-win32-x86_64-2008plus-ssl-4.0.1/data" net:
#bindIp: 127.0.0.1
port: 27017
setParameter:
enableLocalhostAuthBypass: false
```
## 5.4 Linux系統中的安裝啟動和連線
步驟如下:
(1)先到官網下載壓縮包 mongod-linux-x86_64-4.0.10.tgz 。
(2)上傳壓縮包到Linux中,解壓到當前目錄:
```
tar -xvf mongodb-linux-x86_64-4.0.10.tgz
```
(3)移動解壓後的資料夾到指定的目錄中:
```
mv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb
```
(4)新建幾個目錄,分別用來儲存資料和日誌:
```
#資料儲存目錄
mkdir -p /mongodb/single/data/db
#日誌儲存目錄
mkdir -p /mongodb/single/log
```
(5)新建並修改配置檔案
```
vi /mongodb/single/mongod.conf
```
配置檔案的內容如下:
```python
systemLog:
#MongoDB傳送所有日誌輸出的目標指定為檔案
# #The path of the log file to which mongod or mongos should send all diagnostic logging information
destination: file
#mongod或mongos應向其傳送所有診斷日誌記錄資訊的日誌檔案的路徑
path: "/mongodb/single/log/mongod.log"
#當mongos或mongod例項重新啟動時,mongos或mongod會將新條目附加到現有日誌檔案的末尾。
logAppend: true
storage:
#mongod例項儲存其資料的目錄。storage.dbPath設定僅適用於mongod。
##The directory where the mongod instance stores its data.Default Value is "/data/db". dbPath: "/mongodb/single/data/db"
journal:
#啟用或禁用永續性日誌以確保資料檔案保持有效和可恢復。
enabled: true
processManagement:
#啟用在後臺執行mongos或mongod程序的守護程序模式。
fork: true
net:
#服務例項繫結的IP,預設是localhost
bindIp: localhost,192.168.0.2
#bindIp
#繫結的埠,預設是27017
port: 27017
```
(6)啟動MongoDB服務
```
[root@bobohost single]# /usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 90384
child process started successfully, parent exiting
```
注意:
如果啟動後不是 successfully ,則是啟動失敗了。原因基本上就是配置檔案有問題。
通過程序來檢視服務是否啟動了:
```
[root@bobohost single]# ps -ef |grep mongod
root 90384 1 0 8月26 ? 00:02:13 /usr/local/mongdb/bin/mongod -f /mongodb/single/mongod.conf
```
(7)分別使用mongo命令和compass工具來連線測試
提示:如果遠端連線不上,需要配置防火牆放行,或直接關閉linux防火牆
```
#檢視防火牆狀態
systemctl status firewalld
#臨時關閉防火牆 systemctl stop firewalld
#開機禁止啟動防火牆
systemctl disable firewalld
```
(8)停止關閉服務
停止服務的方式有兩種:快速關閉和標準關閉,下面依次說明:
(一)快速關閉方法(快速,簡單,資料可能會出錯)
目標:通過系統的kill命令直接殺死程序:
殺完要檢查一下,避免有的沒有殺掉
```
#通過程序編號關閉節點
kill -2 54410
```
【補充】
如果一旦是因為資料損壞,則需要進行如下操作(瞭解):
1)刪除lock檔案:
```
rm -f /mongodb/single/data/db/*.lock
```
2)修復資料:
```
/usr/local/mongdb/bin/mongod --repair --dbpath=/mongodb/single/data/db
```
(二)標準的關閉方法(資料不容易出錯,但麻煩):
目標:通過mongo客戶端中的shutdownServer命令來關閉服務
主要的操作步驟參考如下:
```
//客戶端登入服務,注意,這裡通過localhost登入,如果需要遠端登入,必須先登入認證才行。
mongo --port 27017
//#切換到admin庫
use admin
//關閉服務
db.shutdownServer()
```
# 六、Xshell連結(Mongo命令)
```
1.本地連線:在bin目錄中敲mongo。(或者把bin目錄做成環境變數)
2.或者 mongo --host=127.0.0.1 --port=27017
```
# 七、Compass-圖形化介面客戶
到MongoDB官網下載MongoDB Compass,
地址:https://www.mongodb.com/download-center/v2/compass?initial=true
如果是下載安裝版,則按照步驟安裝;如果是下載加壓縮版,直接解壓,執行裡面的 MongoDBCompassCommunity.exe 檔案即可。
# 八、常用基礎命令
## 8.1 案例需求
存放文章評論的資料存放到MongoDB中,資料結構參考如下:
資料庫:articledb
| 專欄文章評論 | comment | | |
| -------------- | -------------- | ---------------- | ------------------------- |
| 欄位名稱 | 欄位含義 | 欄位型別 | 備註 |
| _id | ID | Objectld或String | Mongo的主鍵欄位 |
| articleid | 文章ID | String | |
| content | 評論的容 | String | |
| userid | 評論ID | String | |
| nickname | 評論人暱稱 | String | |
| createdatetime | 評論的日期時間 | Date | |
| likenum | 點贊數 | int32 | |
| replynum | 回覆數 | int32 | |
| state | 狀態 | String | 0:不可見;1:可見 |
| parentid | 上級ID | String | 如果為0表示文章的頂級評論 |
## 8.2 資料庫操作
### 8.2.1 選擇和建立資料庫
**選擇和建立資料庫的語法格式**
```
use 資料庫名稱
```
**如果如據庫不存在則自動建立**,例如:
```
use test # 沒有就建立,有就切換
```
**檢視有許可權檢視的所有的資料庫命令**
```
show dbs
或
show databases
```
注意:在MongoDB中,集臺只有在內容插入後才會建立!就是說,建立集合(資料表)後,必須要再插入一個文件(記錄),集合才會真正的建立
### 8.2.2 檢視當前正在使用的資料庫命令
```
db
```
MongoDB中預設的資料庫為test,如果你沒有選擇資料庫,集合將存放再test資料庫中
### 8.2.3 預設自帶的三個庫作用
```
admin: 從許可權的角度來看,這是"root"資料庫。要是將一個使用者新增到這個資料庫,這個使用者自動繼承所有資料庫的許可權。一些特 定的伺服器端命令也只能從這個資料庫執行,比如列出所有的資料庫或者關閉伺服器。
local: 這個資料永遠不會被複制,可以用來儲存限於本地單臺伺服器的任意集合
config: 當Mongo用於分片設定時,config資料庫在內部使用,用於儲存分片的相關資訊
```
### 8.2.4 資料庫的刪除
MongoDB 刪除資料庫的語法格式如下:
```
db.dropDatabase() # 刪除當前所在的庫
```
## 8.3 集合操作
集合,類似關係型資料庫中的表。
可以顯示的建立,也可以隱式的建立。
### 8.3.1 集合的命名規範:
```
1.集合名不能是空字串""。
2.集合名不能含有\0字元(空字元),這個字元表示集合名的結尾。
3.集合名不能以"system."開頭,這是為系統集合保留的字首。
4.使用者建立的集合名字不能含有保留字元。有些驅動程式的確支援在集合名裡面包含,這是因為某些系統生成的集合中包含該字元。除 非你要訪問這種系統建立的集合,否則千萬不要在名字裡出現$。
```
### 8.3.2 集合的顯示建立(瞭解)
基本語法格式:
```
db.createCollection(name) # name: 要建立的集合名稱
eg:建立集合index
db.createCollection("index")
```
檢視當前庫中的表:show tables命令
```
show collections
或
show tables
```
### 8.3.3 集合的隱士建立
當向一個集合中插入一個文件的時候,如果集合不存在,則會自動建立集合
提示:通常我們使用隱式建立文件即可。
### 8.3.4 集合的刪除
集合刪除語法格式如下:
```
db.collection.drop()
或
db.集合名.drop()
返回值
如果成功刪除選定集合,則 drop() 方法返回 true,否則返回 false
```
## 8.4 文件的基本操作
文件(document)的資料結構和 JSON 基本一樣。
所有儲存在集合中的資料都是 BSON 格式
### 8.4.1 文件鍵命名規範
```
1)鍵不能含有\0 (空字元)。這個字元用來表示鍵的結尾。
2)"."點和$有特別的意義,只有在特定環境下才能使用。
3)以下劃線"_"開頭的鍵是保留的(不是嚴格要求的)。
```
### 8.4.2 文件的插入
#### (1)單個文件插入
使用insert() 或 save() 方法向集合中插入文件,語法如下:insert
```
db.collection.insert(
,
{
writeConcern: ,
ordered:
}
)
#解釋:
collection:代表集合名稱,如果沒有集合就會隱士建立
```
引數:
| Parameter | Type | Description |
| ------------ | ----------------- | ------------------------------------------------------------ |
| document | document or array | 要插入到集合中的文件或文件陣列。(json格式) |
| writeConcern | document | Optional. A document expressing the write concern. Omit to use the default write concern. See Write Concern.Do not explicitly set the write concern for the operation if run in a transaction. To use write concern with transactions, see Transactions and Write Concern. |
| ordered | boolean | 可選。如果為真,則按順序插入陣列中的文件,如果其中一個文件出現錯誤,MongoDB將返回而 不處理陣列中的其餘文件。如果為假,則執行無序插入,如果其中一個文件出現錯誤,則繼續處理 陣列中的主文件。在版本2.6+中預設為true |
演示:
要向comment的集合(表)中插入一條測試資料:
```
db.comment.insert(
{"articleid":"100000","content":"今天天氣真好,陽光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null}
)
```
提示:
```
1)comment集合如果不存在,則會隱式建立
2)mongo中的數字,預設情況下是double型別,如果要存整型,必須使用函式NumberInt(整型數字),否則取出來就有問題了。
3)插入當前日期使用 new Date()
4)插入的資料沒有指定 _id ,會自動生成主鍵值
5)如果某欄位沒值,可以賦值為null,或不寫該欄位。
```
執行後,如下,說明插入一個數據成功了。
```
WriteResult({ "nInserted" : 1 })
```
#### (2)批量插入
語法:insertMany
```
db.collection.insertMany(
[ , , ... ],
{
writeConcern: ,
ordered:
}
)
```
引數:
| Parameter | Type | Description |
| ------------ | ----------------- | ------------------------------------------------------------ |
| document | document or array | 要插入到集合中的文件或文件陣列。(json格式) |
| writeConcern | document | Optional. A document expressing the write concern. Omit to use the default write concern. See Write Concern.Do not explicitly set the write concern for the operation if run in a transaction. To use write concern with transactions, see Transactions and Write Concern. |
| ordered | boolean | 可選。一個布林值,指定Mongod例項應執行有序插入還是無序插入。預設為true。 |
演示:
批量插入多條文章評論:
```
db.comment.insertMany([
{"_id":"1","articleid":"100001","content":"我們不應該把清晨浪費在手機上,健康很重要,一杯溫水幸福你我 他。","userid":"1002","nickname":"相忘於江湖","createdatetime":new Date("2019-0805T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
{"_id":"2","articleid":"100001","content":"我夏天空腹喝涼開水,冬天喝溫開水","userid":"1005","nickname":"伊人憔 悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
{"_id":"3","articleid":"100001","content":"我一直喝涼開水,冬天夏天都喝。","userid":"1004","nickname":"傑克船 長","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
{"_id":"4","articleid":"100001","content":"專家說不能空腹吃飯,影響健康。","userid":"1003","nickname":"凱 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
{"_id":"5","articleid":"100001","content":"研究表明,剛燒開的水千萬不能喝,因為燙 嘴。","userid":"1003","nickname":"凱撒","createdatetime":new Date("2019-0806T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}
]);
```
提示:
```
插入時指定了 _id ,則主鍵就是該值。
如果某條資料插入失敗,將會終止插入,但已經插入成功的資料不會回滾掉。
因為批量插入由於資料較多容易出現失敗,因此,可以使用try catch進行異常捕捉處理,測試的時候可以不處理。如以下(瞭解):
```
```
try {
db.comment.insertMany([
{"_id":"1","articleid":"100001","content":"我們不應該把清晨浪費在手機上,健康很重要,一杯溫水幸福你我 他。","userid":"1002","nickname":"相忘於江湖","createdatetime":new Date("2019-0805T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
{"_id":"2","articleid":"100001","content":"我夏天空腹喝涼開水,冬天喝溫開水","userid":"1005","nickname":"伊人憔 悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
{"_id":"3","articleid":"100001","content":"我一直喝涼開水,冬天夏天都喝。","userid":"1004","nickname":"傑克船 長","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
{"_id":"4","articleid":"100001","content":"專家說不能空腹吃飯,影響健康。","userid":"1003","nickname":"凱 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
{"_id":"5","articleid":"100001","content":"研究表明,剛燒開的水千萬不能喝,因為燙 嘴。","userid":"1003","nickname":"凱撒","createdatetime":new Date("2019-0806T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}
]);
} catch (e) {
print (e);
}
```
### 8.4.3 文件的基本查詢
查詢資料的語法格式如下:
```
db.collection.find(, [projection])
```
引數:
| Parameter | Type | Description |
| ---------- | -------- | ------------------------------------------------------------ |
| query | document | 可選。使用查詢運算子指定選擇篩選器。若要返回集合中的所有文件,請省略此引數或傳遞空文件 ( {} )。 |
| projection | document | 可選。指定要在與查詢篩選器匹配的文件中返回的欄位(投影)。若要返回匹配文件中的所有欄位, 請省略此引數。 |
演示:
#### (1)查詢所有
```
db.comment.find()
或
db.comment.find({})
```
這裡你會發現每條文件會有一個叫_id的欄位,這個相當於我們原來關係資料庫中表的主鍵,當你在插入文件記錄時沒有指定該欄位, MongoDB會自動建立,其型別是ObjectID型別。 如果我們在插入文件記錄時指定該欄位也可以,其型別可以是ObjectID型別,也可以是MongoDB支援的任意型別。
#### (2)條件查詢
比如我想查詢userid為1003的記錄
```
db.comment.find({userid:'1003'})
```
如果你只需要返回符合條件的第一條資料,我們可以使用findOne命令來實現,語法和find一樣
如:查詢使用者編號是1003的記錄,但只多返回符合條件的第一條記錄:
```
db.comment.findOne({userid:'1003'})
```
#### (3)投影查詢
如果要查詢結果返回部分欄位,則需要使用投影查詢(不顯示所有欄位,只顯示指定的欄位)。
1:顯示
0:不顯示
如:查詢結果只顯示 _id、userid、nickname :
```
>db.comment.find({userid:"1003"},{userid:1,nickname:1})
{ "_id" : "4", "userid" : "1003", "nickname" : "凱撒" }
{ "_id" : "5", "userid" : "1003", "nickname" : "凱撒" }
```
預設 _id 會顯示。
如:查詢結果只顯示 、userid、nickname ,不顯示 _id :
```
>db.comment.find({userid:"1003"},{userid:1,nickname:1,_id:0})
{ "userid" : "1003", "nickname" : "凱撒" }
{ "userid" : "1003", "nickname" : "凱撒" }
```
再例如:查詢所有資料,但只顯示 _id、userid、nickname :
```
>db.comment.find({},{userid:1,nickname:1,content:1})
```
### 8.4.4 文件的更新
更新文件的語法:
```
db.collection.update(query, update, options)
//或
db.collection.update(
,
,
{
upsert: ,
multi: ,
writeConcern: ,
collation: ,
arrayFilters: [ , ... ],
hint: // Available starting in MongoDB 4.2
}
)
```
#### (1)覆蓋修改
如果我們想修改_id為1的記錄,點贊量為1001,輸入以下語句:
```
db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
```
執行後,我們會發現,這條文件除了likenum欄位其它欄位都不見
#### (2)區域性修改
$set:
為了解決這個問題,我們需要使用修改器$set來實現,命令如下:
我們想修改_id為2的記錄,瀏覽量為889,輸入以下語句:
```
db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}})
```
#### (3)批量修改
{multi:true}
更新所有使用者為 1003 的使用者的暱稱為 凱撒大帝
```
//預設只修改第一條資料
db.comment.update({userid:"1003"},{$set:{nickname:"凱撒2"}})
//修改所有符合條件的資料
db.comment.update({userid:"1003"},{$set:{nickname:"凱撒大帝"}},{multi:true})
```
提示:如果不加後面的引數,則只更新符合條件的第一條記錄
#### (4)列值增長的修改
如果我們想實現對某列值在原有值的基礎上進行增加或減少,可以使用 $inc 運算子來實現。
需求:對3號資料的點贊數,每次遞增1
```
db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
```
### 8.4.5 刪除文件
刪除文件的語法結構:
```
db.集合名稱.remove(條件)
```
以下語句可以將資料全部刪除,請慎用
```
db.comment.remove({})
```
如果刪除_id=1的記錄,輸入以下語句
```
db.comment.remove({_id:"1"})
```
## 8.5 文件的分頁查詢
### 8.5.1 統計查詢
統計查詢使用count()方法,語法如下
```
db.collection.count(query, options)
```
引數:
```
query:查詢選擇條件
options:可選。用於修改計數的額外選項
```
演示:
#### (1)統計所有記錄
統計comment集合的所有的記錄數:
```
db.comment.count()
```
#### (2)按條件統計記錄數
例如:統計userid為1003的記錄條數
```
db.comment.count({userid:"1003"})
```
提示:
預設情況下 count() 方法返回符合條件的全部記錄條數
### 8.5.2 分頁列表查詢
可以使用limit()方法來讀取指定數量的資料,使用skip()方法來跳過指定數量的資料。
基本語法如下所示
```
>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
```
#### (1)limit限制查詢條數
如果你想返回指定條數的記錄,可以在find方法後呼叫limit來返回結果(TopN),預設值20,例如:
```
db.comment.find().limit(3) # 查詢前3條記錄
```
#### (2)skip跳過條數
skip方法同樣接受一個數字引數作為跳過的記錄條數。(前N個不要),預設值是0
```
db.comment.find().skip(3) # 跳過前3條
```
#### (3)分頁查詢
每頁2個,第二頁開始:跳過前兩條資料,接著值顯示3和4條資料
```
//第一頁 db.comment.find().skip(0).limit(2)
//第二頁 db.comment.find().skip(2).limit(2)
//第三頁 db.comment.find().skip(4).limit(2)
```
## 8.5.3 排序查詢
sort() 方法對資料進行排序,sort() 方法可以通過引數指定排序的欄位,並使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而 -1 是用 於降序排列。
語法如下:
```
db.COLLECTION_NAME.find().sort({KEY:1})
或
db.集合名稱.find().sort(排序方式)
```
例如:
對userid降序排列,並對訪問量進行升序排列
```
db.comment.find().sort({userid:-1,likenum:1})
```
提示:
skip(), limilt(), sort()三個放在一起執行的時候,執行的順序是先 sort(), 然後是 skip(),後是顯示的 limit(),和命令編寫順序無關。
## 8.6 文件的更多查詢
### 8.6.1 正則複雜查詢
MongoDB的模糊查詢是通過正則表示式的方式實現的。格式為:
```
db.collection.find({field:/正則表示式/})
或
db.集合.find({欄位:/正則表示式/})
```
提示:正則表示式是js的語法,直接量的寫法
例如,我要查詢評論內容包含“開水”的所有文件,程式碼如下:
```
db.comment.find({content:/開水/})
```
如果要查詢評論的內容中以“專家”開頭的,程式碼如下:
```
db.comment.find({content:/^專家/})
```
### 8.6.2 比較查詢
<, <=, >, >= 這個操作符也是很常用的,格式如下:
```
db.集合名稱.find({ "field" : { $gt: value }}) // 大於: field > value db.集合名稱.find({ "field" : { $lt: value }}) // 小於: field < value db.集合名稱.find({ "field" : { $gte: value }}) // 大於等於: field > = value db.集合名稱.find({ "field" : { $lte: value }}) // 小於等於: field <= value db.集合名稱.find({ "field" : { $ne: value }}) // 不等於: field != value
```
示例:查詢評論點贊數量大於700的記錄
```
db.comment.find({likenum:{$gt:NumberInt(700)}})
```
### 8.6.3 包含查詢
包含使用$in操作符。 示例:查詢評論的集合中userid欄位包含1003或1004的文件
```
db.comment.find({userid:{$in:["1003","1004"]}})
```
不包含使用$nin操作符。 示例:查詢評論集合中userid欄位不包含1003和1004的文件
```
db.comment.find({userid:{$nin:["1003","1004"]}})
```
### 8.6.4 條件連線查詢
我們如果需要查詢同時滿足兩個以上條件,需要使用$and操作符將條件進行關聯。(相 當於SQL的and) 格式為:
```
$and:[ { },{ },{ } ]
```
示例:查詢評論集合中likenum大於等於700 並且小於2000的文件:
```
db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})
```
如果兩個以上條件之間是或者的關係,我們使用 操作符進行關聯,與前面 and的使用方式相同 格式為
```
$or:[ { },{ },{ } ]
```
示例:查詢評論集合中userid為1003,或者點贊數小於1000的文件記錄
```
db.comment.find({$or:[ {userid:"1003"} ,{likenum:{$lt:1000} }]})
```
## 8.7 常用命令小結
```
選擇切換資料庫:use 庫名
插入資料:db.comment.insert({bson資料})
查詢所有資料:db.comment.find();
條件查詢資料:db.comment.find({條件})
查詢符合條件的第一條記錄:db.comment.findOne({條件})
查詢符合條件的前幾條記錄:db.comment.find({條件}).limit(條數)
查詢符合條件的跳過的記錄:db.comment.find({條件}).skip(條數)
修改資料:db.comment.update({條件},{修改後的資料}) 或db.comment.update({條件},{$set:{要修改部分的欄位:資料})
修改資料並自增某欄位值:db.comment.update({條件},{$inc:{自增的欄位:步進值}})
刪除資料:db.comment.remove({條件})
統計查詢:db.comment.count({條件})
模糊查詢:db.comment.find({欄位名:/正則表示式/})
條件比較運算:db.comment.find({欄位名:{$gt:值}})
包含查詢:db.comment.find({欄位名:{$in:[值1,值2]}})或db.comment.find({欄位名:{$nin:[值1,值2]}})
條件連線查詢:db.comment.find({$and:[{條件1},{條件2}]})或db.comment.find({$or:[{條件1},{條件2}]})
```
# 九、索引
## .1 索引概述
索引支援在MongoDB中高效地執行查詢。如果沒有索引,MongoDB必須執行全集合掃描,即掃描集合中的每個文件,以選擇與查詢語句 匹配的文件。這種掃描全集合的查詢效率是非常低的,特別在處理大量的資料時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的效能是非 常致命的。
如果查詢存在適當的索引,MongoDB可以使用該索引限制必須檢查的文件數。
索引是特殊的資料結構,它以易於遍歷的形式儲存集合資料集的一小部分。索引儲存特定欄位或一組欄位的值,按欄位值排序。索引項的排 序支援有效的相等匹配和基於範圍的查詢操作。此外,MongoDB還可以使用索引中的排序返回排序結果。
官網文件:https://docs.mongodb.com/manual/indexes/
瞭解:
MongoDB索引使用B樹資料結構(確切的說是B-Tree,MySQL是B+Tree)
## 9.2 索引的型別
### 9.2.1 單欄位索引
MongoDB支援在文件的單個欄位上建立使用者定義的升序/降序索引,稱為單欄位索引(Single Field Index)。 對於單個欄位索引和排序操作,索引鍵的排序順序(即升序或降序)並不重要,因為MongoDB可以在任何方向上遍歷索引。
![](https://gitee.com/guyouyin/image/raw/master/img/20200509105349.png)
### 9.2.2 複合索引
MongoDB還支援多個欄位的使用者定義索引,即複合索引(Compound Index)。
複合索引中列出的欄位順序具有重要意義。例如,如果複合索引由 { userid: 1, score: -1 } 組成,則索引首先按userid正序排序,然後 在每個userid的值內,再在按score倒序排序。
![](https://gitee.com/guyouyin/image/raw/master/img/20200509132801.png)
### 9.2.3 其他索引
地理空間索引(Geospatial Index)、文字索引(Text Indexes)、雜湊索引(Hashed Indexes)。
為了支援對地理空間座標資料的有效查詢,MongoDB提供了兩種特殊的索引:返回結果時使用平面幾何的二維索引和返回結果時使用球面 幾何的二維球面索引。
## 9.3 索引管理操作
### 9.3.1 索引的檢視
```
db.集合名.getIndexes()
[
{
"v" : 2, # mongodb引擎的版本號(不用管)
"key" : {
"_id" : 1 # 預設主鍵
},
"name" : "_id_", # 索引名稱
"ns" : "jeff.comment" # 索引的位置
}
]
```
### 9.3.2 建立索引
```
db.集合名.createIndex(keys, options)
```
```
引數:
keys:包含欄位和值對的文件,其中欄位是索引鍵,值描述該欄位的索引型別。對於欄位上的升序索引,請 指定值1;對於降序索引,請指定值-1。比如: {欄位:1或-1} ,其中1 為指定按升序建立索引,如果你 想按降序來建立索引指定為 -1 即可。另外,MongoDB支援幾種不同的索引型別,包括文字、地理空 間和雜湊索引。
options:可選。包含一組控制索引建立的選項的文件。有關詳細資訊,請參見選項詳情列表。
```
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. |
提示:
注意在 3.0.0 版本前建立索引方法為 db.collection.ensureIndex() ,之後的版本使用了 db.collection.createIndex() 方法, ensureIndex() 還能用,但只是 createIndex() 的別名。
演示:
#### (1)建立單欄位索引
對 userid 欄位建立索引
```
db.comment.createIndex({userid:1}) # 升序
# 檢視一下索引
db.comment.getIndexes()
```
#### (2)建立符合索引
對 userid 和 nickname 同時建立複合(Compound)索引:
```
db.comment.createIndex({userid:1,nickname:-1})
# 檢視一下索引
db.comment.getIndexes()
```
### 9.3.3 刪除索引
#### (1)指定索引刪除
```
db.集合名.dropIndex(索引)
eg:
db.comment.dropIndex({userid:1}) # 刪除{userid:1}索引
```
#### (2)刪除所有索引
_id索引永遠不會被刪除
```
db.集合名.dropIndexes()
eg:
db.comment.dropIndexes() # 刪除comment集合的所有索引
```
## 9.4 索引的使用
### 9.4.1 執行計劃
分析查詢效能 通常使用執行計劃來檢視查詢的情況,如查詢耗費的時間、是 否基於索引查詢等。
那麼,通常,我們想知道,建立的索引是否有效,效果如何,都需要通過執行計劃檢視。
```
db.集合名.find(query,options).explain(options)
eg:
db.comment.find({userid:"1003"}).explain() # 檢視根據userid查詢資料的情況
```
```
"stage" : "COLLSCAN", # 全域性掃描
"stage" : "FETCH", # 抓取
```
#### (1)沒有索引的情況
![](https://gitee.com/guyouyin/image/raw/master/img/20200509151403.png)
#### (2)有索引的情況
![](https://gitee.com/guyouyin/image/raw/master/img/20200509151641.png)
### 9.4.2 覆蓋查詢
![](https://gitee.com/guyouyin/image/raw/master/img/20200509152