MongoDB 基礎知識

基本概念

  • 文檔是 MongoDB 中數據的基本單元,很是相似於關係型數據庫中的行,但更具備表現力;
  • 集合 Collection 能夠看做是一個動態模式(Dynamic Schema)的表;
  • MongoDB 的一個實例能夠擁有多個相互獨立的數據庫 ( Database),每個數據庫都擁有本身的集合;
  • 每個文檔都有一個特殊的鍵 _id ,這個鍵在文檔所屬的集合中是惟一的;
  • MongoDB 自帶了一個簡單但功能強大的 JavaScript Shell ,可用於管理 MongoDB 的實例或數據操做。

文檔

文檔是 MongoDB 的核心概念,文檔就是鍵值對的有序集,下面的便是以 JavaScript 語言表現的一份文檔:javascript

{
    "greeting" : "Hello, world!"
}

在絕大多數狀況下,文檔的鍵是字符串(除了少數例外),鍵可使用任意的UTF-8 字符。java

  • 鍵不能含有 \0 (空字符),這個字符用於表示鍵的結尾;
  • .$ 具備特殊意義,只能在特定環境下使用,一般這兩個字符是被保留的,若是使用不當的話,驅動程序會有提示。

MongoDB 不但區分類型,還區分大小寫,下面的兩個文檔是不一樣的:正則表達式

{
    "foo" : "bar"
}

與:mongodb

{
    "Foo" : "bar"
}

另外一個重要的事項是, MongoDB 的文檔不能有重複的鍵,例如:shell

{
    "greeting" : "Hello, world!",
    "greeting" : "Hello, MongoDB!"
}

文檔中的鍵/值對是有序的:數據庫

{
    "x" : 1,
    "y" : 2
}

與:express

{
    "y" : 2,
    "x" : 1
}

是不一樣的。json

集合

集合就是一組文檔。若是將 MongoDB 中的一個文檔比喻爲關係型數據庫中的一行,那麼一個集合就至關於一張表。vim

動態模式

集合是動態模式的,這意味着一個集合裏面的文檔但是各式各樣的,如何下面兩個文檔就能夠出現一個集合裏面:數組

{
    "greeting" : "Hello, world!"
},
{
    "foo" : 5
}

上面的兩個文檔,除了值不一樣外,鍵也不一樣,可是不建議像上面那樣作,一樣的文檔,咱們通常仍是放在一個特定的集合裏面更好,不論是速度、效率仍是結構上來說,都要更好。

命名

集合使用名稱進行標識,集合名稱能夠是知足下列條件的任意 UTF-8 字符串:

  • 集合名不能是空字符串("");
  • 集合名稱不能包含 \0 字符(空字符),這個字符表示集合名的結束;
  • 集合名不能以 system. 開頭,這是爲系統集合保留的前綴,例如: system.users 這個集合保存着數據庫的用戶信息,而 system.namespaces 集合保存着全部數據庫集合的信息;
  • 用戶建立的集合不能在集合名中包含保留字符 $ ,由於某些系統生成的集合中飲食 $

子集合

組織集合的一種慣例是使用 . 分隔不一樣命名空間的了集合,好比一個具備博客功能的應用可能包含兩個集合,分別是 blog.postsblog.authors

數據庫

在 MongoDB 中,多個文檔組成集合,而多個集合能夠組成數據庫,一個 MongoDB 能夠承載我個數據庫,每一個數據庫擁有 0 個或者多個集合,每一個數據庫都有獨立的權限,即使是在磁盤上,不一樣的數據庫也放置在不一樣的文件中。

數據庫經過名稱來標識,這點與集合相似,數據庫名能夠是知足如下條件的任意 UTF-8 字符串:

  • 不能是空字符串 ""
  • 不能含有 /\."*<>:|?$(一個空格)、\0(空字符);
  • 數據庫名區分大小寫,即便在不區分大小寫的文件系統中也是如此,簡單起見,全部的數據庫均爲小寫;
  • 數據庫名最多爲64個字節。

在這裏咱們須要記住一點,數據庫名最終會變成文件系統中的文件,而數據庫名就是相應的文件名,這是數據庫名有如此多限制的緣由。

另外,有一些數據庫名是保留的,能夠直接訪問這些有特殊語言的數據庫,以下:

  • admin

    從身份驗證的角度來說,這是 root 數據庫,若是有一個用戶添加到這個數據庫,則這個用戶將擁有全部數據庫的權限;

  • local

    這個數據庫永遠都不能夠複製,且一臺服務器上全部的本地集合均可以存儲在這個數據訓中;

  • config

    MongoDB 用戶分片設置時,分片信息會存儲在 config 數據庫中。

把數據庫名稱添加到集合名稱前,獲得集合的徹底限定名,即 命名空間 namespace,命名空間的長度不得超過 121 字節,而實際應用中,應該小於100字節。

啓動 MongoDB

一般,MongoD 做爲網絡服務器來運行,客戶端可鏈接到該服務器並執行操做。要安裝 MongoDB ,能夠從官方網站下載相應的適合你係統的版本(http://www.mongodb.org/downloads)。下載完成以後,解壓,並把解壓以後獲得的文件夾複製或者移到至最終你想安裝的目錄便可。

我將其安裝在了 /Users/pantao/Workspace/MongoDB 這個目錄,同時,我將 MongoDBbin 目錄加入了PATH變量中:

vi ~/.bash_profile

加入以下一行:

export PATH="/Users/pantao/Workspace/MongoDB/bin:$PATH"

保存以後,運行:

source ~/.bash_profile

這個時候,我就能夠直接在任何地方啓動 MongoDB 或者進行相關的數據庫操做了,使用 mongod 命名啓動服務器:

pantaodeMacBook-Pro:MongoDB pantao$ mongod
2015-04-21T10:00:06.302+0800 I STORAGE  [initandlisten] exception in initAndListen: 29 Data directory /data/db not found., terminating
2015-04-21T10:00:06.302+0800 I CONTROL  [initandlisten] dbexit:  rc: 100

出現上面這個錯誤是由於 /data/db 目錄不存在,若啓動時,不指定任何參數, MongoDB 會默認使用 /data/db 目錄存儲數據,咱們可使用 --dbpath 來指定其它的路徑,好比我使用的是下面這樣的命令啓動的:

mongod --dbpath /Users/pantao/Workspace/MongoDB/db

上面這個是個人工做目錄,直接將 MongoDB 的程序和數據庫放在一塊兒,我方便學習管理。

MongoDB Shell

MongoDB 自帶有 JavaScript Shell ,能夠Shell 中使用命令行與 MongoDB 實例交互,Shell很是有用,經過它能夠執行管理操做,檢查運行實例,亦或是作其它嘗試。

運行 shell

使用 mongo 命令啓動 shell

pantaodeMacBook-Pro:MongoDB pantao$ mongo
MongoDB shell version: 3.0.2
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    http://docs.mongodb.org/
Questions? Try the support group
    http://groups.google.com/group/mongodb-user
Server has startup warnings: 
2015-04-21T10:03:18.997+0800 I CONTROL  [initandlisten] 
2015-04-21T10:03:18.997+0800 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
>

啓動時, shell 會打印出當前 shell 的版本號,鏈接到了哪一個庫以及一些幫助信息等,這是一個功能完備的 JavaScript 解釋器,能夠運行任意 JavaScript 程序,好比使用 JavaScript 標準庫或者定義以及調用 JavaScript 函數等。

MongoDB 客戶端

shell 是一個獨立的 MongoDB客戶端,啓動時, shell 會連到 MongoDB 服務器的 test 數據庫,並將數據庫鏈接賦值給合局變量 db ,這個變量是經過 shell訪問 MongoDB 的主要入口點,可使用 db 查看當前指向哪一個數據庫:

> db
test

除了JavaScript語法外,MongoDB 還提供了一些語法糖,以幫助咱們更好的管理數據庫,好比:

> use foobar
switched to db foobar

這個時候咱們能夠看到數據庫已經切換到 foobar 數據庫了:

> db
foobar

Shell 中的基本操做

shell 中查看查看或操做數據,會用到4個基本操做:建立讀取更新刪除,即 CRUD 操做;

建立

經過 db.createCollection() 函數能夠先建立一個集合:

> db.createCollection("blog")
{ "ok" : 1 }

insert 能夠將一個文檔添加到集合中:

> post = {"title": "這是一篇文章", "content": "這是文章的內容。","date" : new Date()}
{
    "title" : "這是一篇文章",
    "content" : "這是文章的內容。",
    "date" : ISODate("2015-04-21T02:22:52.899Z")
}

這是一個有效的 MongoDB 文檔,因此能夠用 insert 方法將其保存到集合中。

> db.blog.insert(post)
WriteResult({ "nInserted" : 1 })

接着可使用 find 方法查找這篇文章:

> db.blog.find()
{ "_id" : ObjectId("5535b574b705494e688e218a"), "title" : "這是一篇文章", "content" : "這是文章的內容。", "date" : ISODate("2015-04-21T02:22:52.899Z") }

能夠看到咱們的數據都已經完整的保存下來了,同時,MongoDB 還爲咱們自動生成了一個 _id 參數。

讀取

findfindOne 方法能夠用於查詢集合裏的文檔:

> db.blog.findOne()
{
    "_id" : ObjectId("5535b574b705494e688e218a"),
    "title" : "這是一篇文章",
    "content" : "這是文章的內容。",
    "date" : ISODate("2015-04-21T02:22:52.899Z")
}

findfindOne 能夠接受一個查詢文檔做爲限定條件,使用 find 時,shell 會自動顯示最多 20 個匹配的文檔,也能夠獲取更多文檔。

更新

使用 update 修改博客文章,它至少接受兩個參數,第一個是限定條件,第二個是新文檔,好比咱們如今要給 post 加上評論列表:

> post.comments = []
[ ]

而後,用新版本的 post 替換標題爲 《這是一篇文章》的文章:

> db.blog.update({"title":"這是一篇文章"},post)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
    "_id" : ObjectId("5535b574b705494e688e218a"),
    "title" : "這是一篇文章",
    "content" : "這是文章的內容。",
    "date" : ISODate("2015-04-21T02:22:52.899Z"),
    "comments" : [ ]
}

能夠看到,comments 已經更新到原來的那個 post 中去了。

刪除

使用 remove 能夠刪除集合中的文檔,若沒有任何限定參數,它將刪除集合中的全部數據,也能夠像下面這樣,刪除標題爲《這是一篇文章》的文章:

> db.blog.remove({"title":"這是一篇文章"})
WriteResult({ "nRemoved" : 1 })
> db.blog.find()
>

數據類型

基本的數據類型

MongoDB 的文檔與 JavaScript 中的對象相近,於是能夠認爲相似於 JavaScript 中的 JSONJSON 是一種簡單的數據表示方式,僅有 6種數據類型,分別爲 nullboolnumberstringarrayobject

MongoDB在保留 JSON 基本鍵/值對特性的基礎上,添加了其它的一些數據類型:

null

用於表示空值或者不存在的字段:

{
    "x" : null
}

bool 布爾型

只有兩個值 truefalse

{
    "x" : true,
    "y" : false
}

number 數值

shell 默認使用 64位浮點型數值,對於整型值,可以使用 NumberInt 類或 NumberLong 類:

{
    "pi" : 3.14,
    "x" : 3,
    "ni" : NumberInt("3"),
    "nl" : NumberLong("3")
}

string 字符串

UTF-8 類型的字符串均可以表示爲字符串類型的數據:

{
    "x" : "this is a string.",
    "y" : "這是一個NB的字符串"
}

date 日期

日期被存儲 爲自新紀元以來通過的毫秒數,不存儲時區

{
    "x" : new Date()
}

regular expression 正則表達式

在進行查詢時,咱們能夠直接使用正則表達式做爲值,語法與 javascript 的相同:

{
    "x" : /foobar/i
}

array 數組

數據列表或數據集能夠表達爲數組:

{
    "a" : ["x", "y" , "z"]
}

object id 對象ID

對象ID是一個 12 字節的ID,它是文檔的惟一標識:

{
    "x" : ObjectId()
}

object id 以如下方式生成:

|0|1|2|3|4|5|6|7|8|9|10|11|
|  時間戳  | 機器|PID|   計數器   |
  • 時間戳在前,對於索引效率提升有必定的做用;同時它也帶了必定的時間信息,一些驅動能夠從 ObjectId 獲取這些信息;
  • 時間戳與機器碼還有 PID 組合在一塊兒,提供了秒級別的惟一性,機器碼是機器主機名的散列值(hash);
  • PID確保了同一臺主機不一樣進程產生的 ObjectId 的惟一性,接下來的字節
  • 最後的計數器,確保同一臺機器同一個進程在同一秒內產生的 ObjectId 是不同的,一秒鐘最多容許每一個進程擁有 2563 個不一樣的ObjectId。
自動生成 _id

若插入文檔時,沒有提供 _id

object 內嵌文檔

文檔能夠嵌套其它文檔,被嵌套的文檔做爲父文檔的值:

{
    "o" : {
        "name" : "child object"
    }
}

binary data 二進制數據

任意字節的字符串,它不直直接在 shell 中使用,若是要將非 utf-8 字符保存到數據庫中,二進制數據是惟一的實現方式。

javascript 代碼

查詢和文檔中能夠包括作生意 JavaScript 代碼:

{
    "script" : function() { /* code goes here */ }
}

timestamps 時間戳

不一樣於 Date 類型的時間戳值,它是一個 64位長度的值,它是:

  • 前面的 32位爲 time_t 值,(Unix 時間戳)
  • 後32位是一個在給定的時間內的自增值

使用 MongoDB shell

除了像前面那樣使用 shell 鏈接數據庫外,咱們還能夠在鏈接數據時指定服務器地址、端口號以及數據名等參數,好比:

mongo mongo-db.xingzhewujiang.com:30000/ahaInsight

啓動時,可讓 mongo shell 不鏈接任何的 mongod ,能夠經過 --nodb 參數:

mongo --nodb

啓動以後,咱們能夠在須要時執行 new Mongo(hostname) 命令就能夠鏈接到想要鏈接的 mongod 了:

> conn = new Mongo("host.name:30000")
connection to host.name:30000
> db = conn.getDB("dbname")
dbname

在使用 shell 的過程當中,還能夠隨時使用 help 命令查看幫助:

help
    db.help()                    help on db methods
    db.mycoll.help()             help on collection methods
    sh.help()                    sharding helpers
    rs.help()                    replica set helpers
    help admin                   administrative help
    help connect                 connecting to a db help
    help keys                    key shortcuts
    help misc                    misc things to know
    help mr                      mapreduce

    show dbs                     show database names
    show collections             show collections in current database
    show users                   show users in current database
    show profile                 show most recent system.profile entries with time >= 1ms
    show logs                    show the accessible logger names
    show log [name]              prints out the last segment of log in memory, 'global' is default
    use <db_name>                set current database
    db.foo.find()                list objects in collection foo
    db.foo.find( { a : 1 } )     list objects in foo where a == 1
it                           result of the last line evaluated; use to further iterate
    DBQuery.shellBatchSize = x   set default number of items to display on shell
    exit                         quit the mongo shell

使用 shell 執行腳本

除了交互式的使用 shell 外,咱們還能夠將命令保存在一個文件中,好比 script.js ,而後使用 mongo 命令直接執行它們,一次能夠傳入多個文件名,mongo shell 會依次執行傳入的腳本,而後退出:

mongo script.js script1.js

若是但願指定主機和端口來運行上面的腳本,還能夠這樣作:

mongo --quiet host.name:30000/dbname script.js script1.js

--quiet 可讓 mongo shell不打印 MongoDB shell version... 這樣的提示信息。

在交互式的命令行中,還可使用 load() 函數加載並運行腳本:

> load("script.js")
i am a string printed by script.js
>

知道這個以後,咱們能夠把一些能用的函數保存到一個文件裏面,而後再將他們加載進 shell 交互界面裏面來:

建立一個名爲 connectTo.js 的文件,內容以下:

javascript/**
 * 連接到指定的數據庫,而後將 db 指向這個連接
 */
var connectTo = function(port, dbname) {
    if (!port) {
        port = 27017;
    }

    if (!dbname) {
        dbname = "test"
    }

    db = connect("localhost:" + port + "/" + dbname)
    return db
}

而後咱們進入 shell

bash> typeof connectTo
undefined
> load("connectTo.js")
true
> typeof connectTo
function
>

咱們可使用腳本讓能用的管理和任務自動化,好比,咱們想在每一次 shell 啓用時,都加載上面定義的那個函數,這個時候咱們能夠用到一個名爲 .mongorc.js 的文件。

在本身的家目錄中(不一樣的系統都不同),新建一個名爲 .mongorc.js 的文件,而後寫入下面這些內容:

print("你好,我來自 .mongorc.js 文件")

而後,從新進入 shell

mongo
MongoDB shell version: 3.0.2
connecting to: test
你好,我來自 .mongorc.js 文件
>

刪除危險的函數

該文件通常用得最多的就是用於刪除一些比較危險的 shell 輔助函數,好比刪除數據庫、索引等,好比下面這樣的:

javascriptvar no = function() {
    print("Not no my watch.");
}

// 禁止刪除數據庫
db.dropDatabase = DB.prototype.dropDatabase = no;

// 禁止刪除集合
DBCollection.prototype.drop = no;

// 禁止刪除索引
DBCollection.prototype.dropIndex = no;

定製提示信息

shell 默認的提示是一個 > 符號,咱們能夠對該符號進行定製,好比最簡單的是,在每個提示符前面加上一個當前時間,這樣咱們就能夠很容易大概的知道,一些須要長時間執行的操做到底用了多久時間了:

javascriptprompt = function() {
    return (new Date()) + "> ";
}

再一次進入 shell

bashmongo
MongoDB shell version: 3.0.2
connecting to: test
Tue Apr 21 2015 13:06:40 GMT+0800 (CST)>
Tue Apr 21 2015 13:06:43 GMT+0800 (CST)>db
test

另外一個方便的提示是顯示當前正在使用的數據庫:

javascriptprompt = function() {
    if (typeof db == 'undefined') {
        return '(nodb)>';
    }

    // 檢查最後使用的數據庫操做
    try {
        db.runCommand({getLastError:1});
    }
    catch (e) {
        print(e);
    }
    return db + "> ";
}

再一次進入 shell

bashmongo
MongoDB shell version: 3.0.2
connecting to: test
test>

更好的編輯工具

shell 對多行編輯頗有限,若編輯了多行,忽然發現前面有一行有錯誤,這是不能修改的,可是它提供了一種方法,讓你能夠在 shell 中很訪問的使用外部的第三方編輯器,保存並退出編輯器以後,會對你修改的值進行從新解析,並從新加載回 shell 中,一樣使用 .mongorc.js,在其中加入下面這一行:

EDITOR = "/usr/bin/vim"

而後進入 shell:編輯一個複雜一點兒的變量:

bashmongo
MongoDB shell version: 3.0.2
connecting to: test
> var post = {
... title: "這是一篇文章的內容",
... content: "這是一篇文章的標題",
... author: "潘韜"
... }
> post
{ "title" : "這是一篇文章的內容", "content" : "這是一篇文章的標題", "author" : "潘韜" }
> edit post
> post
{ "title" : "這是一篇文章的標題", "content" : "這是一篇文章的內容", "author" : "潘韜" }
>

一些變態的集合名稱的使用

絕大多數時候,咱們可使用 db.collectionName 這種方式訪問一個數據庫中的集合,可是也有例外,好比 db.version 就不能訪問到名稱爲 version 的集合,由於 versiondb 的一個方法名,能夠用來顯示當前的數據庫版本信息。那麼咱們就得使用其它的方法了,好比:

> db.getCollection("version");
test.version

有些時候,咱們的集合裏面還可能使用了不少變態的奇怪的名稱,好比 &$*%#,使用 db.&$*%# 是非法的,可是咱們卻可使用 db.getCollection("&$*%#") 來獲取該集合,一樣的,咱們還有一種更加直接的方法,就是相似於JavaScript的數組訪問語法,像下面這樣:

db["&$*%#"].find()
相關文章
相關標籤/搜索