探索 MongoDB--转
原文地址:https://www.ibm.com/developerworks/cn/opensource/os-mongodb4/index.html?mhq=mongodb&mhsrc=ibmsearch_a
MongoDB 是什么?
近幾年來,我們已經看到不同于傳統關系模型的數據庫管理系統越來越受歡迎。它的核心是 NoSQL 概念,這個共同的術語表示不使用 SQL 語言與數據庫交互的數據庫軟件。比較著名的 NoSQL 項目之一就是 MongoDB,一個開放源碼、面向文檔的數據庫,它在類似于 JSON 的文檔集合存儲數據。MongoDB 相比其他 NoSQL 數據庫的優勢之一是它強大的、基于文檔的查詢語言,由于查詢非常容易轉換,這使得從關系數據庫到 MongoDB 的過渡變得簡單。
MongoDB 是用 C++ 語言編寫的。它在類似于 JSON 的文檔中存儲數據(使用 BSON,一個 JSON 的二進制版本),存儲數據的方式是使用鍵/值對。MongoDB 優于其他文檔數據庫的一個特性是它很容易將 SQL 語句轉換成 MongoDB 查詢函數調用。這使得當前使用關系數據庫的組織很容易遷移到 MongoDB。它也很容易安裝和使用,有二進制和驅動程序兩種形式,兼容主流操作系統和編程語言。
MongoDB 是一個開放源碼項目,其數據庫基于 GNU AGPL (Affero General Public License) version 3.0 的許可。此許可是 GNU GPL 的一個修正版,它彌補了版權限制不適用于軟件使用而僅適用軟件分發的漏洞。這對于在云中存儲而不經常安裝在客戶端設備上的軟件當然是重要的。使用常規 GPL ,您會感覺到實際上無法進行分發,因此潛在地規避了許可條款。
AGPL 只適用于它自己的數據庫應用程序,不適用于 MongoDB 的其他組成部分。允許開發人員從各種編程語言連接 MongoDB 的官方驅動程序在 Apache License Version 2.0 許可下分發。 MongoDB 文檔的使用基于 Creative Commons 許可。
面向文檔的數據庫
面向文檔的數據庫與傳統關系數據庫有很大不同。與在類似于表的固定結構中存儲數據不同,面向文檔的數據庫在松散定義的文檔中存儲數據。利用關系數據庫管理系統(RDBMS)表,如果您需要添加一個新的列,您需要改變表本身的定義,這會將該列添加到每一條現有的記錄(雖然可能是一個空值)。這是由于 RDBMS 嚴格的基于模式的設計。然而,利用文檔時,您可在不改變任何其他文檔的情況下為個別文檔添加新屬性。這是因為面向文檔的數據庫在設計上通常非模式化的。
另一個基本差異是面向文檔的數據庫不在文檔之間規定嚴格的關系。這有助于維護它們的非模式化設計。這與十分依賴規范化數據存儲關系的關系型數據庫有很大不同。與在一個單獨的存儲區存儲相關數據不同,在文檔數據庫中它們被嵌入文檔本身,這要比將引用存儲到另一個存儲相關數據的文檔中要快得多,因為每個引用都需要一個附加查詢。
對于許多應用程序來說,如果它需要在一個父文檔中包含自成體系的數據,這種面向文檔的數據庫非常適合。一個好的示例(可在 MongoDB 文檔中找到)是博客文章和評論。評論只適用于一篇文章,所以把它們從該文章分開是無意義的。在 MongoDB 中,有關博客文章的文檔只需要一個?comments?屬性來存儲該文章的評論。而如果使用關系數據庫,則可能需要一個帶 ID 主關鍵字的 comments 表、一個帶 ID 主關鍵字的 posts 表和一個中間的映射表 post_comments,此映射表用于定義哪個評論屬于哪篇文章。這為本應很簡單的事增加了不必要的復雜性。
不過,如果您必須分開存儲相關數據,在 MongoDB 中也可以簡單地使用一個獨立的集合來完成。另一個好的示例是您把客戶訂單信息存儲在 MongoDB 文檔中。它通常包含以下信息:客戶、訂單、訂單條目和產品信息。使用 MongoDB ,您可以在獨立的集合中存儲客戶、產品和訂單,但是您需要把訂單項數據嵌入在相關的訂單文檔中。然后,您需要使用類似于外部關鍵字的 ID 來引用?products?和?customers?集合。由于這種混合方法非常簡單,使得 MongoDB 成為已習慣于使用 SQL 的開發 人員的極好選擇。如上所述,應該花點時間細心地為每個單獨用例選擇合適的方法,因為相比于從其他集合中引用數據,采用在文檔中嵌入數據的方法將獲得顯著的性能收益。
功能概覽
MongoDB 不僅僅是一個基本的鍵/值對存儲數據庫,讓我們簡單地看一下它的其他特性:
- 可用于 Windows?、Mac OS X、Linux? 和 Solaris 的官方二進制版本,可用于自構建的源代碼分發
- 可用于 C、C#、C++、Haskell、Java?、JavaScript、Perl、PHP、Python、Ruby 和 Scala 的官方驅動程序,以及廣泛可用于其他語言的社區支持的驅動程序。
- Ad-hoc JavaScript 查詢讓您能夠使用基于任何文檔屬性的任何條件來查找數據。這些查詢對應于 SQL 查詢的功能,使 SQL 開發人員能夠很直觀地編寫 MongoDB 查詢。
- 支持查詢中的正則表達式
- MongoDB 查詢結果存儲在提供過濾、聚合和排序等一系列功能的游標中,包括?limit()、skip()、?sort()、count()、distinct()?和?group()。
- 高級聚合的?map/reduce?實現
- 使用 GridFS 的大文件存儲
- 類似于 RDBMS 的屬性索引支持,您可以直接在文檔的選定屬性上創建索引
- 使用提示、解釋計劃和分析的查詢優化特性
- 類似于 MySQL 的主/從復制
- 基于集合的對象存儲,在需要規范化數據時允許參考查詢
- 通過自動分片功能水平擴展
- 高性能無爭用并發機制的即時更新
- 在線 shell 讓您能夠不安裝 MongoDB 即可試用
- 深入的文檔資料,已出版或正在寫作中的多本圖書
安裝 MongoDB
幸運的是,MongoDB 在各種平臺上的安裝都非常簡單。二進制發行版在 Windows、Mac OS X、 Linux 和 Solaris 上都可以使用,同時,各種包管理器為其他系統提供了簡單的安裝和設置選項。如果您夠勇敢,可以自己編譯源代碼。在本節中,您將學會如何在 Windows 和 OS X 上安裝 MongoDB,在 Windows 上將進程設置為服務或在 OS X 上將進程設置為守護程序。
在 Windows 上安裝
在 Windows 上安裝 MongoDB 十分簡單。在 Web 瀏覽器中,轉到 http://www.mongodb.org/downloads 并下載適用于 Windows 的最新版本的穩定產品。如果您正使用 64 位版本的 Windows 操作系統,建議使用 64 位版本。如果您不確定,就使用 32 位版本。
把壓縮文件解壓到 C:\ 驅動器,這將創建一個名稱類似于 mongodb-win32-i386-1.6.4 的文件夾。為了簡便,將這個文件夾重命名為 mongo 。接下來,需要創建一個數據目錄。在 Windows 資源管理器中,轉到 C:\ 驅動器的根目錄下并創建一個名為 data 的新文件夾。在此文件夾中,創建一個名為 db 的文件夾。
您現在可以啟動 MongoDB 服務器。使用 Windows 資源管理器導航至 C:\mongo\bin 并雙擊 mongod.exe。關閉打開的命令提示符窗口將會停止 MongoDB 服務器。因此,將 MongoDB 服務器設置為 Windows 服務更為方便。我們現在來完成。
打開命令提示符窗口 (啟動 > 運行 >,輸入?cmd?并按?確定),然后發出清單 1?中的命令。
清單 1. 將 MongoDB 服務器設置為一個服務
| 1 2 3 | > cd \mongo\bin > mongod --install --logpath c:\mongo\logs --logappend --bind_ip 127.0.0.1 --directoryperdb |
您將看到清單 2?中的輸出。
清單 2. 創建服務成功
| 1 2 3 4 | all output going to c:\mongo\logs Creating service MongoDB. Service creation successful. Service can be started from the command line via 'net start "MongoDB"'. |
將 Mongo 作為服務安裝后,您現在可以用以下命令啟動它:> net start "MongoDB"
您將看到清單 3?中的輸出。
清單 3. Mongo 成功啟動
| 1 2 | The Mongo DB service is starting. The Mongo DB service was started successfully. |
您現在可以運行 MongoDB shell 客戶端。如果現在有一個命令提示符窗口打開,確認位于 c:\mongo\bin 文件夾中并輸入以下命令:> mongo.
另一種方法是,在 Windows 資源管理器中導航至 C:\mongo\bin 并雙擊 mongo.exe。無論選擇哪種方法來啟動 shell,您都應看到如清單 4中所示的提示。
清單 4. 啟動 shelll
| 1 2 3 | MongoDB shell version: 1.8.1 connecting to: test > |
如果您不想在 Mac OS X 計算機上設置 MongoDB,現在可以跳過本節的下一部分,轉到“入門指南”,您將學習如何使用 shell 客戶端與 MongoDB 服務器進行交互。
在 Mac OS X 中安裝
假設您現在使用 Mac OS X 的 64 位版本,以下步驟詳細說明了如何下載 MongoDB 的 64 位 OS X 二進制版本,解壓它,配置并開始使用,還將教您如何作為守護程序運行 MongoDB。
首先,啟動 Terminal (Applications>Utilities>Terminal)。在 Terminal 窗口,運行清單 5?中的命令。
清單 5. 在 Mac OS X上設置 MongoDB
| 1 2 3 4 5 | $ cd ~ $ curl http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-1.6.4.tgz > mongo.tgz $ tar xzf mongo.tgz $ mv mongodb-osx-x86_64-1.8.1/ mongo $ mkdir -p /data/db |
MongoDB 現在設置完成并準備使用。在繼續之前,最好把 MongoDB 添加到您的路徑中,執行以下命令:?$ nano ~/.bash_profile.
此文件可能還不存在。在這種情況下,添加以下行:?export PATH={$PATH}:~/mongo/bin.
按 ctrl + O 保存文件,然后在提示符下按 Enter。再按 ctrl + X 退出。現在,用以下命令重新載入 bash 配置文件:?$ source ~/.bash_profile.
您現在已經準備好啟動 MongoDB。只需發出以下命令就可以啟動:?$ mongod.
這將作為前臺進程啟動 MongoDB 數據庫服務器。如果您想作為后臺守護程序啟動 MongoDB ,發出以下命令:?$ sudo mongod --fork --logpath /var/log/mongodb.log --logappend.
將要求您輸入密碼,在此提示下輸入 Mac OS X 管理員密碼。
無論您選擇哪種方法啟動 MongoDB,服務器現在都能運行。如果作為前臺進程啟動,您將需要一個單獨的 Terminal 標簽或窗口來啟動客戶端。要啟動客戶端,只需使用命令:$ mongo
將會看到清單 6?中的提示:
清單 6. 啟動客戶端
| 1 2 3 | MongoDB shell version: 1.8.1 connecting to: test > |
在下一節中,您將學習如何使用 MongoDB shell 來創建數據庫、集合、文檔等。
MongoDB 使用入門
MongoDB 發行版包含一個 shell 應用程序,使您能夠完全控制數據庫。通過使用 shell,您可以使用服務器端 JavaScript 功能來創建和管理數據庫、集合、文件和索引。這使快速啟動和運行 MongoDB 變得容易。在本節中,您將學習如何啟動 shell 并了解一些進行基本數據庫存儲和檢索的命令。
MongoDB shell
MongoDB shell 應用程序包含在 MongoDB 發行版的 bin 文件夾中。在 Windows 系統中,它就是 mongo.exe 應用程序。在 Windows 資源管理器中,雙擊此程序即可啟動 shell 。在基于 UNIX? 的操作系統中(包括 Mac OS X),您可通過在一個終端窗口(假使您按照以上說明將 MongoDB 目錄加入到路徑)執行 mongo 命令啟動 MongoDB shell。
第一次啟動 shell 時,您將看到清單 7?中消息。
清單 7. 啟動 shell 時的消息
| 1 2 3 | MongoDB shell version: 1.8.1 connecting to: test > |
您現在已連接到本地 MongoDB 服務器,尤其是“測試”服務器。在下一節中,您將學習如何創建數據庫、文檔和集合。如果您在某個階段需要幫助,只需要在 Mongo shell 提示符下發出 "help" 命令。?圖 1?顯示了典型的幫助命令的輸出。
圖 1. Mongo shell?help命令的輸出
如果您想查看 MongoDB 函數背后的源代碼,只需簡單地在 shell 中輸入函數的名稱,它將會輸出 JavaScript 源代碼。例如,輸入?connect?后按回車鍵,您將看到用于連接 MongoDB 數據庫的源代碼。
創建數據庫、集合和文檔
默認情況下,Mongo shell 連接到“測試”數據庫。如果要切換到一個不同的數據庫,使用 “use 數據庫名” 命令。如果數據庫不存在,在您將數據添加到數據庫時,MongoDB 將會創建它。用以下命令切換到 "mymongo" 數據庫:?> use mymongo.
shell 將返回以下信息:?switched to db mymongo.
這時,數據庫仍未真正存在,因為它沒有包含任何數據。在 MongoDB 中,數據以集合的形式存儲。如果需要,您可以分割文檔。下面創建一個文檔并把它存儲到一個名為 "colors" 的新集合中:?> db.colors.save({name:"red",value:"FF0000"});.
通過查詢數據庫來驗證文檔已保存:?> db.colors.find();.
您將看到類似于下面的響應(_id?屬性是唯一標識符,與您的結果可能會不同):?{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }.
MongoDB 中的文檔以 BSON(二進制 JSON)形式存儲。通過 Mongo shell,可以使用類似于 JSON 的語法插入數據,其中每個文檔都是一個鍵-值對形式的對象。在這個例子中,我們創建一個具有兩個屬性的文檔:name?和?value,值分別為?red?和?FF0000(標準紅色的十六進制表示形式)。
您可能已經注意到,不需要預定義?colors?集合,當您使用存儲功能插入一個條目時,文檔將自動創建。
在這個例子中,您創建了一個非常簡單的文檔。然而,使用類似于 JSON 的語法可以創建更復雜的文檔。考慮下面的 JSON 文檔,它表示了一個訂單或發票(參見?清單 8)。
清單 8. 創建一個簡單的文檔
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | { ????order_id: 109384, ????order_date: new Date("12/04/2010"), ????customer: { ????????name: "Joe Bloggs", ????????company: "XYZ Inc.", ????????phone: "(555) 123-4567" ????}, ????payment: { ????????type: "Cash", ????????amount: 4075.99, ????????paid_in_full: true ????}, ????items: [ ????????{ ????????????sku: "ABC1200", ????????????description: "A sample product", ????????????quantity: 1, ????????????price_per_unit: 75.99, ????????}, { ????????????sku: "XYZ3400", ????????????description: "An expensive product", ????????????quantity: 2, ????????????price_per_unit: 2000 ????????} ????], ????cashier_id: 340582242 } |
您可以看到,這些文檔可以存儲包括字符串、整數、浮點數、日期、對象、數組等的各種數據類型。在清單 8 中,訂單條目直接嵌入在訂單文檔中,使得以后查詢文檔時檢索信息快得多。
由于 MongoDB shell 使用 JavaScript,當您與數據庫交互時,可以編寫規則的 JavaScript 結構 。以清單 9為例,它創建一個字符文檔集合,每個集合都包含字符的字符串表示形式及其關聯的 ASCII 代碼。
清單 9. 創建一個字符文檔集合
| 1 2 3 4 5 6 | > var chars = "abcdefghijklmnopqrstuvwxyz" > for(var i =0; i<chars.length; i++) {??? ... var char = chars.substr(i, 1);????????? ... var doc = {char:char, code: char.charCodeAt(0)}; ... db.alphabet.save(doc); ... } |
此循環將創建 26 個文檔,代表字母表的每個小寫字母,每個文檔包含字符本身及其 ASCII 字符碼。在下一節中,您將學習如何用不同方法檢索數據。
檢索數據
在最后一節中,您不僅會學習如何向 MongoDB 數據庫中插入數據,而且會實際學習如何使用最基本的數據檢索函數 find。我們以上一節結尾時創建的字母表集合為例,學習使用 find 命令:?db.alphabet.find();。
這將生成如清單 10?所示的響應。
清單 10. 生成響應
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | > db.alphabet.find() { "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 } { "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 } { "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 } { "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 } { "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 } { "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 } { "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 } { "_id" : ObjectId("4cfa4adf528bad4e29beec96"), "char" : "k", "code" : 107 } { "_id" : ObjectId("4cfa4adf528bad4e29beec97"), "char" : "l", "code" : 108 } { "_id" : ObjectId("4cfa4adf528bad4e29beec98"), "char" : "m", "code" : 109 } { "_id" : ObjectId("4cfa4adf528bad4e29beec99"), "char" : "n", "code" : 110 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9b"), "char" : "p", "code" : 112 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9c"), "char" : "q", "code" : 113 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9d"), "char" : "r", "code" : 114 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9e"), "char" : "s", "code" : 115 } { "_id" : ObjectId("4cfa4adf528bad4e29beec9f"), "char" : "t", "code" : 116 } has more > |
默認情況下,find()?函數會檢索集合中的所有文檔,但只顯示前 20 個文檔。給出命令?it?將檢索剩余的 6 個文檔(參見清單 11)。
清單 11. 檢索剩余的 6 個文檔
| 1 2 3 4 5 6 7 8 | > it { "_id" : ObjectId("4cfa4adf528bad4e29beeca0"), "char" : "u", "code" : 117 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 } > |
find()?函數實際上向查詢結果集返回了一個指針,在本例中是檢索所有文件。如果沒有分配一個變量或沒有執行其他函數,它將在屏幕上默認打印一個樣例結果集。要顯示所有結果集,應執行以下命令:?> db.alphabet.find().forEach(printjson);。
這將打印結果集中的每條記錄,而不是顯示一個子集。接下來我們將了解更多有關使用指針和查詢來篩選數據的方法。
查詢數據
MongoDB 最強大的功能之一是它對 ad-hoc 查詢的強大支持,其工作方式與傳統關系數據庫幾乎一樣,它篩選和返回 BSON 文檔而不是表中的行。這種方法使它有別于其他文檔存儲,對于 SQL 開發人員來說,這一點很難掌握。利用 MongoDB ,相對復雜的 SQL 查詢可以簡單地轉換為 JavaScript 函數調用。在本節中,您將學習可讓您在 MongoDB 中查詢數據的各種函數,以及如何建立索引來幫助優化查詢,就像在 DB2、MySQL 或 Oracle 中一樣。
基本查詢
在上一節中,您學習了如何使用 find 函數來檢索所有文檔。find 函數接受一系列參數來篩選返回的結果。例如,在上面創建的字母表集合中,您能用以下命令找到 "char" 屬性的值為 "q" 的任何記錄:?> db.alphabet.find({char: "o"});。
這將返回以下響應:?{ "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 }。
如果您想要返回編碼小于或等于 100 的所有字符,可以使用以下命令:?> db.alphabet.find({code:{$lte:100}});.
這將返回清單 12?中的結果,與您期望的一致。
清單 12. 結果
| 1 2 3 4 | { "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 } |
MongoDB 支持各種條件運算符,包括:
- $lt?(小于)
- $lte?(小于等于)
- $gt?(大于)
- $gte?(大于等于)
- $all?(匹配數組中的所有值)
- $exists?(檢查字段是否存在)
- $mod?(模數)
- $ne?(不等)
- $in?(匹配數組一個或多個值)
- $nin?(匹配數組中的零值)
- $or?(匹配一個或另一個查詢)
- $nor?(不匹配查詢)
- $size?(匹配具有預定數量元素的任何數組)
- $type?(匹配具有指定 BSON 數據類型的值)
- $not?(不等于)
有關所有這些運算符的詳細信息,請參閱 MongoDB 文檔(參見參考資料中的鏈接)。
您可以使用 find 函數中的第二個參數來限制查詢返回的字段。例如,下面的查詢只返回所有文檔中編碼值范圍在 102 至 105 之間的?char?屬性:?> db.alphabet.find({code:{$in:[102,103,104,105]}}, {char: 1});.
這將產生?清單 13?中的結果。
清單 13. 結果
| 1 2 3 4 | { "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f" } { "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g" } { "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h" } { "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i" } |
在下一節中,您將學習如何創建索引來加速查詢。
索引
MongoDB 索引與關系數據庫中的索引十分相似。您可以基于任何屬性建立索引。此外,索引后的字段可以是任何數據類型,包括一個對象或數組。與 RDBMS 索引相似,可以使用多個屬性創建復合索引,也可創建唯一索引,確保不存在重復的值。
要創建一個基本索引,使用?ensureIndex?函數。下面使用字母表集合中的?code?和?char?屬性創建一個索引。(參見清單 14)。
清單 14. 創建索引
| 1 2 | > db.alphabet.ensureIndex({code: 1}); > db.alphabet.ensureIndex({char: 1}); |
可以使用 dropIndex 和 dropIndexes 函數刪除索引。可參閱 MongoDB 文檔獲得更多信息。
排序
要對結果集進行排序,可以對指針應用 sort 函數。字母表集合已經基于 code 和 char 屬性的升序排序,下面按 code 屬性的升序排序,返回一個子集:?> db.alphabet.find({code: {$gte: 118}}).sort({code: 0});。
這將返回清單 15?中的結果。
清單 15. 結果
| 1 2 3 4 5 | { "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 } { "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 } |
如果在上一條命令中為 sort 函數提供參數?{code: 1} ,它將會以升序對結果排序。為了確保高效的查詢,一定要為排序的數據屬性添加索引。
使用 skip 和 limit 分頁結果
通常在處理數據結果集時,一次只想檢索一個子集,也許是在網頁上提供分頁結果。在 MySQL 中,您通常使用?LIMIT?關鍵字來實現。您在 MongoDB 中只需使用 skip 和 limit 函數即可實現這一功能。要返回字母表集合中的前 5 個文檔,可執行以下操作:?> db.alphabet.find().limit(5);。
這將返回清單 16?中的結果。
清單 16. 結果
| 1 2 3 4 5 | { "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 } { "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 } { "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 } |
要獲得下一頁,使用以下命令:?> db.alphabet.find().skip(5).limit(5);。
如清單 17?所示,這將獲取接下來的 5 條記錄。
清單 17. 獲取接下來的 5 條記錄
| 1 2 3 4 5 | { "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 } { "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 } { "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 } { "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 } { "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 } |
分組函數和聚合
MongoDB 的查詢引擎也使得對數據應用聚合和分組函數變得非常簡單。這類似于 SQL 中的相應功能。可以說,應用最廣泛的函數是 count() 函數:> db.alphabet.find().count();。
這將返回 26。您可以簡單對篩選出的查詢結果進行計數:?> db.alphabet.find({code: {$gte: 105}}).count();。
以上命令將返回 18。
另一個有用的聚合函數是?distinct。利用它可返回針對某個屬性的一組不同的值。由于所有數據都是唯一的,因此字母表集合不是一個合適的例子。我們向本文開頭創建的?colors?集合中添加一些記錄(參見清單 18)。
清單 18. 向?color?集合中添加記錄
| 1 2 3 | > db.colors.save({name:"white",value:"FFFFFF"}); > db.colors.save({name:"red",value:"FF0000"});? > db.colors.find(); |
假定您沒有刪除?colors?集合,您將看到?清單 19?中的響應。
清單 19. 響應
| 1 2 3 | { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" } { "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" } { "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" } |
您可以看到,在這個集合中明顯有兩個 red 文檔。現在使用?distinct?函數從此集合中獲得一組唯一的?name?屬性:?> db.colors.distinct("name");。
這將返回:?[ "red", "white" ]。
值得注意的是,您在執行其他查詢函數時不能在指針和結果集上執行 distinct 函數,而應直接在集合上執行。還應注意,它返回的不是一組文檔,而是一組值。
MongoDB 還為執行類似于 SQL 中的?GROUP BY?表達式的操作提供了?group?函數。group?函數是一個異常復雜的函數,所以我在這里只給出一個簡短的示例。例如,我們要按 name 值來分組計算文檔數。在 SQL 中,可以定義表達式為?SELECT name, COUNT(*) FROM colors GROUP BY name;。
要在 MongoDB 中執行此查詢,需要使用清單 20?中的命令。
清單 20. 使用?group?函數
| 1 2 3 4 5 6 | > db.colors.group( ... {key: {name: true}, ... cond: {}, ... initial: {count: 0},????????????????????????????????? ... reduce: function(doc, out) { out.count++; } ... }); |
這將產生在清單 21?中的結果。
清單 21. 結果
| 1 2 3 4 5 6 7 8 9 10 | [ ????{ ????????"name" : "red", ????????"count" : 2 ????}, ????{ ????????"name" : "white", ????????"count" : 1 ????} ] |
如果需要執行高級聚合或使用大型數據集,MongoDB 還包含一個?map/reduce?實現,讓您能夠完成這一任務。上面介紹的 group 函數在分片的 MongoDB 安裝中無法工作,所以如果您要使用分片,一定要使用?map/reduce?來替代 group 函數。
更新現有數據
在 MongoDB shell 中,更新文檔非常容易。在前面創建的 colors 集合中,有兩條?red?記錄。要從記錄中取出一個并將它更改為?black,且值屬性為?000000?(黑色的十六進制值)。首先,可以使用 findOne 函數來檢索值為 red 的單個項目,根據需要更改其屬性,并將文檔存儲到數據庫中。
獲取名稱為?red?的單一文檔并把它存儲在?blackDoc?變量中:?> var blackDoc = db.colors.findOne({name: "red"});。
接下來,使用點表示法修改文檔的屬性(參見清單 22)。
清單 22. 修改文檔屬性
| 1 2 | > blackDoc.name = "black"; > blackDoc.value = "000000"; |
在保存之前,檢查文檔是否正確(它應該有?_id?屬性,否則只是插入了一條新記錄而不是覆蓋 red 記錄):?> printjson(blackDoc);。
如果返回結果類似于清單 23,則表示您準備好了。
清單 23. 結果
| 1 2 3 4 5 | { ????"_id" : ObjectId("4cfa43ff528bad4e29beec57"), ????"name" : "black", ????"value" : "000000" } |
最后,使用?save?函數將文檔保存回數據庫中的?colors?集合:?> db.colors.save(blackDoc);。
現在可以使用?find?函數來確保集合是正確的:?> db.colors.find();。
這將返回類似于清單 24?的結果。如果您有 4 條記錄,您就錯了。
清單 24. 結果
| 1 2 3 | { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" } { "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" } { "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" } |
除了 Mongo shell 之外,您可以在應用程序中使用 update 函數來將更改應用到現有數據。有關 update 函數的更多信息,請參閱 MongoDB 文檔。
刪除數據
要刪除 MongoDB 中的數據,可使用?remove?函數。請注意這適用于 MongoDB shell 程序,某些驅動程序可能使用 delete 函數或者沒有。如有必要,可查閱某個具體實現的相關文檔。
remove 函數與 find 函數工作方式類似。要刪除 colors 集合中與名稱?white?相匹配的任何文檔,可使用以下命令:?> db.colors.remove({name:"white"});。
然后,可以檢查此文檔是否已刪除:?> db.colors.find();。
如果正確,您將只會看見兩個文檔(參見清單 25)。
清單 25. 刪除數據
| 1 2 | { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" } { "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" } |
要刪除集合中的所有文檔,只需在命令中省略篩選器,類似如下:?> db.colors.remove();。
現在如果您試圖使用 find 函數,將得不到響應,表示一個空的結果集:?> db.colors.find();。
如果文檔存儲在變量中,也可以將此文檔傳送給?remove?函數以刪除它,但這么做非常低效。最好找到這個文檔的?_id?屬性并把它傳送給?remove?函數。
要刪除一個集合,使用以下命令:?> db.colors.drop();。
這將返回以下結果:?true。
現在可以使用?show collections?命令檢查集合確實已被刪除。這將產生清單 26?中的輸出。
清單 26. 使用?show collections?命令
| 1 2 | alphabet system.indexes |
最后,如果您想要刪除整個數據庫,執行如下命令:> db.dropDatabase();。
這將刪除當前選定的數據庫。您將看到以下輸出:?{ "dropped" : "mymongo", "ok" : 1 }.
可以使用?show dbs?命令獲得可用數據庫列表。mymongo?將不會出現在這個列表中。
工具及其他特性
MongoDB 包含一系列用于管理數據庫的有用工具。無論是報表還是備份,它都提供了各種方式來導入和導出數據。在本節中,您將了解如何以 JSON 格式導入和導出文件,以及如何創建用于高效恢復的熱備份文件。您還將學習如何使用?map/reduce?函數作為 Mongo 用于復雜數據聚合的常規查詢函數的一種替代方式。
導入和導出數據
MongoDB 的 bin 目錄包含了一系列工具,可用于以各種格式導入和導出數據。 mongoimport 工具允許您提供一個文件,其中每行包含一個 JSON 、CSV 或 TSV 格式的文檔,并將這些文檔插入 MongoDB 數據庫。由于 MongoDB 使用 BSON 格式,如果希望利用在常規 JSON 中無法使用的 BSON 附加數據類型,在導入 JSON 文檔時需要提供一些說明信息。
mongoexport 工具允許您生成一個文件輸出,其中 MongoDB 數據庫中的每個文檔都以 JSON 或 CSV 格式表示。這對于生成報表非常有用,因為應用程序接受 JSON 或 CSV 數據作為輸入。要生成一個 CSV 文件,需要按輸出文件中顯示的順序提供字段。
備份和恢復數據庫
當需要從 MongoDB 中取出數據以用于其他應用程序或從其他使用 JSON 或 CSV 數據的應用程序中導入數據時,mongoimport 和 mongoexport 工具非常有用。然而,這些工具不能用于獲得定期備份或 MongoDB 數據庫,也不能用于恢復 MongoDB 數據庫。因為 MongoDB 使用 BSON 而不是 JSON 或 CSV ,從這些格式中導入數據時很難保留數據類型。
為了提供適當的備份和恢復功能,MongoDB 提供了兩個工具:mongodump 和 mongorestore。 mongodump 用于生成數據庫的二進制文件備份,mongorestore 用于讀取此文件并使用它恢復數據庫,并根據需要自動創建索引(除非已將 system.indexes.bson 文件從備份目錄中刪除)。
管理工具
MongoDB 還提供了一個基于 Web 的診斷接口,在默認 MongoDB 配置上從?http://localhost:28017/?可以獲得。這個屏幕類似于圖 2。
圖 2. MongoDB 診斷
為了獲得其他管理信息,也可以在 MongoDB shell 中運行以下命令:
- db.serverStatus();
- db.stats();
如果 MongoDB 服務器崩潰,應修復數據庫以檢查錯誤并執行一些數據精簡。可以通過在操作系統命令行中運行?mongod --repair?進行修復,或選擇從 MongoDB shell 運行 db.repairDatabase() 命令。后一個命令在每個數據庫的級別上運行,所以您需要針對服務器上的每個數據庫都運行此命令。
您也可以使用 validate 函數驗證集合數據。如果擁有一個名為 contacts 的集合,可以用?db.contacts.validate() 命令驗證此集合。
MongoDB 有很多其他特性可讓數據庫管理員更輕松,包括各種各樣的第三方管理工具和可用的接口。請參閱 MongoDB 文檔以獲得更多信息。
map/reduce 函數
如果您以前使用過 CouchDB 數據庫,可能熟悉?map/reduce?函數,因為視圖引擎默認使用?map/reduce?函數來篩選和聚合數據。在 MongoDB 中,情況不是這樣的,簡單的查詢和篩選(甚至聚合)不依靠?map/reduce?來完成。不過,MongoDB 確實為聚合大型數據集的應用提供了?map/reduce?實現。
map/reduce?這一主題可能需要一整篇文章來描述。有關 MongoDB 實現的詳細信息,請參閱 MongoDB 文檔。(參見參考資料中的鏈接)。
擴展 MongoDB
鍵/值存儲和面向文檔數據庫最近流行的主要原因是它們占用資源少及其高度可擴展性。為了發揮這些優勢,MongoDB 引入了分片和復制的概念,您將在本節中學習。此外,您還將學習如何在 MongoDB 中使用 GridFS 存儲大文件。最后,您將了解如何對查詢進行分析以優化數據庫的性能。
分片
數據庫基礎架構的一個重要部分就是確保其良好的可擴展性。MongoDB 實現采用一種自動分片機制來確保其橫向擴展,這使得 MongoDB 配置可擴展至數千個節點,具有自動負載平衡、無單點故障和自動故障轉移功能,向 MongoDB 集群添加新機器也非常簡單。
MongoDB 的自動分片特性的好處是它使得從單一服務器轉向分片集群變得非常容易,通過無需或很少需要對所需的程序代碼進行改動。有關自動分片的工作原理及如何實現它的詳細信息,請參閱 MongoDB 文檔。
復制
為了實現故障轉移和冗余,MongoDB 在主從配置中提供了復制特性(類似于 MySQL),從而確保節點之間的高度一致性。也就是說,MongoDB 可以在任何時候使用副本集將某個節點定義為主節點,在故障時另一節點擔負起主節點的任務。
與 CouchDB 使用復制作為擴展機制的思路不同,MongoDB 主要使用復制來確保高度可用性,方法是使用從屬節點作為冗余副本。
有關 MongoDB 復制的更多信息,請參閱文檔(參見參考資料中的鏈接)。
使用 GridFS 的大文件存儲
MongoDB 數據庫以 BSON 文檔存儲數據。BSON 文檔的最大大小是 4MB,這不適合存儲大文件和對象。MongoDB 通過將文件劃分為多個文檔之間的較小塊,使用 GridFS 規范來存儲大文件。
標準 MongoDB 發行版包含將 GridFS 文件添加到本地文件系統以及從本地文件系統檢索 GridFS 文件的命令行工具。另外,所有官方 MongoDB API 驅動程序都包含對 GridFS 的支持。有關詳細信息,請參閱 MongoDB 文檔(參見參考資料)。
結束語
在本文中,您學習了 MongoDB 數據庫管理系統,以及它成為 DBMS 市場受歡迎的 NoSQL 中成長最快的可選產品的原因。您學習了為何要選擇優于傳統 RDBMS 的面向文檔數據庫,以及 MongoDB 提供的各種強大功能。還學習了如何安裝和使用 MongoDB 來存儲和檢索數據,以及它提供的各種工具和可擴展性選項。
相關主題
- 訪問?MongoDB 官方網站。
- 閱讀 Wikipedia 的?MongoDB?條目。
- 訪問?MongoDB 正式文檔。
- 了解有關 MongoDB?map/reduce?函數的更多信息。
- MongoDB 手冊為正確使用 MongoDB 提供了指南。
- 通過 developerWorks 網站學習使用 NoSQL 和分析大數據。
- 閱讀?MongoDB 生產部署的說明,了解企業如何從 MySQL 轉換到 MongoDB。
- 閱讀?MongoDB 思考,了解業界觀念如何轉變。
- 閱讀博客使用 MongoDB 12 個月,了解 Wordnik 如何轉換到 MongoDB。
- 關注 Eltot Horowitz(10gen 的 CTO,10gen 是贊助 MongoDB 的一家公司)有關 MongoDB 的博客。
- 10gen?開發并支持 MongoDB,一個開源、高性能、可擴展、面向文檔的數據庫。
- Java 開發 2.0:MongoDB:擁有 RDBMS 特性的 NoSQL 數據存儲(Andrew Glover,developerWorks,2010 年 9 月):了解所有關于 MongoDB 的自定義 API、交互式 shell、RDBMS 式的動態查詢,以及快速簡單的 MapReduce 計算的更多信息。
- 探索 CouchDB(Joe Lennon,developerWorks,2009 年 3 月): Apache 的開源 CouchDB 提供了存儲數據的新方法,稱為無模式面向文檔的數據庫模型。不同于關系模型的高度結構化的數據存儲方式,CouchDB 以半結構化方式存儲數據,使用基于 JavaScript 的視圖模型來從這些半結構化的文檔生成結構化的聚合和報表結果。
- 下載?MongoDB。
- 隨時關注 developerWorks?技術活動和網絡廣播。
- 訪問 developerWorks?Open source 專區獲得豐富的 how-to 信息、工具和項目更新以及最受歡迎的文章和教程,幫助您用開放源碼技術進行開發,并將它們與 IBM 產品結合使用。
轉載于:https://www.cnblogs.com/davidwang456/articles/10974351.html
總結
以上是生活随笔為你收集整理的探索 MongoDB--转的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MongoDB如何一次插入多条json数
- 下一篇: 瓜子大数据架构