1. 程式人生 > >一篇文章解決MongoDB的所有問題

一篇文章解決MongoDB的所有問題

[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