MongoDB指南---二、MongoDB基礎知識-文檔、集合、數據庫、客戶端

上一篇文章: MongoDB指南---一、MongoDB簡介
下一篇文章: MongoDB指南---三、MongoDB基礎知識-數據類型

MongoDB很是強大但很容易上手。本章會介紹一些MongoDB的基本概念。
文檔是MongoDB中數據的基本單元,很是相似於關係型數據庫管理系統中的行,但更具表現力。
相似地,集合(collection)能夠看做是一個擁有動態模式(dynamic schema)的表。
MongoDB的一個實例能夠擁有多個相互獨立的數據庫(database),每個數據庫都擁有本身的集合。
每個文檔都有一個特殊的鍵"_id", 這個鍵在文檔所屬的集合中是惟一的。
MongoDB自帶了一個簡單但功能強大的JavaScript shell,可用於管理MongoDB的實例或數據操做。git

2.1 文檔

文檔是MongoDB的核心概念。文檔就是鍵值對的一個有序集。每種編程語言表示文檔的方法不太同樣,但大多數編程語言都有一些相通的數據結構,好比映射(map)、散列(hash)或字典(dictionary)。例如,在JavaScript 裏面,文檔被表示爲對象:web

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

這個文檔只有一個鍵"greeting",其對應的值爲"Hello,world!"。大多數文檔會比這個簡單的例子複雜得多,一般會包含多個鍵/值對:mongodb

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

從上面的例子能夠看出,文檔中的值能夠是多種不一樣的數據類型(甚至能夠是一個完整的內嵌文檔,詳見2.6.4節)。在這個例子中,"greeting"的值是一個字符串,而"foo"的值是一個整數。
文檔的鍵是字符串。除了少數例外狀況,鍵可使用任意UTF-8字符。
鍵不能含有0(空字符)。這個字符用於表示鍵的結尾。
.和$具備特殊意義,只能在特定環境下使用(後面的章節會詳細說明)。一般,這兩個字符是被保留的;若是使用不當的話,驅動程序會有提示。
MongoDB不但區分類型,並且區分大小寫。例如,下面的兩個文檔是不一樣的:shell

{"foo" : 3}
{"foo" : "3"}

下面兩個文檔也是不一樣的:數據庫

{"foo" : 3}
{"Foo" : 3}

還有一個很是重要的事項須要注意,MongoDB的文檔不能有重複的鍵。例如,下面的文檔是非法的:編程

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

文檔中的鍵/值對是有序的:{"x" : 1, "y":2}與{"y": 2, "x": 1}是不一樣的。一般,字段順序並不重要,無須讓數據庫模式依賴特定的字段順序(MongoDB會對字段從新排序)。在某些特殊狀況下,字段順序變得很是重要,本書將就此給出提示。
一些編程語言對文檔的默認表示根本就不包含順序問題(如:Python中的字典、Perl和Ruby 1.8中的散列)。一般,這些語言的驅動具備某些特殊的機制,能夠在必要時指定文檔的順序。segmentfault

2.2 集合

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

2.2.1 動態模式

集合是動態模式的。這意味着一個集合裏面的文檔能夠是各式各樣的。例如,下面兩個文檔能夠存儲在同一個集合裏面:瀏覽器

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

須要注意的是,上面的文檔不光值的類型不一樣(一個是字符串,一個是整數),它們的鍵也徹底不一樣。由於集合裏面能夠放置任何文檔,隨之而來的一個問題是:還有必要使用多個集合嗎?這的確值得思考:既然沒有必要區分不一樣類型文檔的模式,爲何還要使用多個集合呢?這裏有幾個重要的緣由。
若是把各類各樣的文檔不加區分地放在同一個集合裏,不管對開發者仍是對管理員來講都將是噩夢。開發者要麼確保每次查詢只返回特定類型的文檔,要麼讓執行查詢的應用程序來處理全部不一樣類型的文檔。若是查詢博客文章時還要剔除含有做者數據的文檔,這會帶來很大困擾。
在一個集合裏查詢特定類型的文檔在速度上也很不划算,分開查詢多個集合要快得多。例如,假設集合裏面一個名爲"type"的字段用於指明文檔是skim、whole仍是chunky monkey。那麼,若是從一個集合中查詢這三種類型的文檔,速度會很慢。但若是將這三種不一樣類型的文檔拆分爲三個不一樣的集合,每次只須要查詢相應的集合,速度快得多。
把同種類型的文檔放在一個集合裏,數據會更加集中。從一個只包含博客文章的集合裏查詢幾篇文章,或者從同時包含文章數據和做者數據的集合裏查出幾篇文章,相比之下,前者須要的磁盤尋道操做更少。
建立索引時,須要使用文檔的附加結構(特別是建立惟一索引時)。索引是按照集合來定義的。在一個集合中只放入一種類型的文檔,能夠更有效地對集合進行索引。
上面這些重要緣由促使咱們建立一個模式,把相關類型的文檔組織在一塊兒,儘管MongoDB對此並無強制要求。服務器

2.2.2 命名

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

  • 集合名不能是空字符串("")。
  • 集合名不能包含0字符(空字符),這個字符表示集合名的結束。
  • 集合名不能以「system.」開頭,這是爲系統集合保留的前綴。例如,system.users這個集 合保存着數據庫的用戶信息,而system.namespaces集合保存着全部數據庫集合的信息。
  • 用戶建立的集合不能在集合名中包含保留字符'$'。由於某些系統生成的集合中包含$,不少驅動程序確實支持在集合名裏包含該字符。除非你要訪問這種系統建立的集合,不然不該該在集合名中包含$。

子集合

組織集合的一種慣例是使用「.」分隔不一樣命名空間的子集合。例如,一個具備博客功能的應用可能包含兩個集合,分別是blog.posts和blog.authors。這是爲了使組織結構更清晰,這裏的blog集合(這個集合甚至不須要存在)跟它的子集合沒有任何關係。
雖然子集合沒有任何特別的屬性,但它們卻很是有用,於是不少MongoDB工具都使用了子集合。

  • GridFS(一種用於存儲大文件的協議)使用子集合來存儲文件的元數據,這樣就能夠與文件內容塊很好地隔離開來。(第6章會詳細介紹GridFS。)
  • 大多數驅動程序都提供了一些語法糖,用於訪問指定集合的子集合。例如,在數據庫shell中,db.blog表明blog集合,而db.blog.posts表明blog.posts集合。

在MongoDB中,使用子集合來組織數據很是高效,值得推薦。

2.3 數據庫

在MongoDB中,多個文檔組成集合,而多個集合能夠組成數據庫。一個MongoDB實例能夠承載多個數據庫,每一個數據庫擁有0個或者多個集合。每一個數據庫都有獨立的權限,即使是在磁盤上,不一樣的數據庫也放置在不一樣的文件中。按照經驗,咱們將有關一個應用程序的全部數據都存儲在同一個數據庫中。要想在同一個MongoDB服務器上存放多個應用程序或者用戶的數據,就須要使用不一樣的數據庫。
數據庫經過名稱來標識,這點與集合相似。數據庫名能夠是知足如下條件的任意UTF-8字符串。

  • 不能是空字符串("")。
  • 不得含有/、、.、"、*、<、>、:、|、?、$(一個空格)、0(空字符)。基本上,只能使用ASCII中的字母和數字。
  • 數據庫名區分大小寫,即使是在不區分大小寫的文件系統中也是如此。簡單起見,數據庫名應所有小寫。
  • 數據庫名最多爲64字節。

要記住一點,數據庫最終會變成文件系統裏的文件,而數據庫名就是相應的文件名,這是數據庫名有如此多限制的緣由。
另外,有一些數據庫名是保留的,能夠直接訪問這些有特殊語義的數據庫。這些數據庫以下所示。

  1. admin

從身份驗證的角度來說,這是「root」數據庫。若是將一個用戶添加到admin數據庫,這個用戶將自動得到全部數據庫的權限。再者,一些特定的服務器端命令也只能從admin數據庫運行,如列出全部數據庫或關閉服務器。

  1. local

這個數據庫永遠都不能夠複製,且一臺服務器上的全部本地集合均可以存儲在這個數據庫中。(第9章會詳細介紹複製及本地數據庫。)

  1. config

MongoDB用於分片設置時(參見第13章),分片信息會存儲在config數據庫中。

把數據庫名添加到集合名前,獲得集合的徹底限定名,即命名空間(namespace)。例如,若是要使用cms數據庫中的blog.posts集合,這個集合的命名空間就是cms.blog.posts。命名空間的長度不得超過121字節,且在實際使用中應小於100字節。(參考附錄B,瞭解MongoDB中集合的命名空間及內部表示的更多信息。)

2.4 啓動MongoDB

一般,MongoDB做爲網絡服務器來運行,客戶端可鏈接到該服務器並執行操做。下載MongoDB(http://www.mongodb.org/downloads)並解壓,運行mongod命令,啓動數據庫服務器:

$ mongod
mongod --help for help and startup options
Thu Oct 11 12:36:48 [initandlisten] MongoDB starting : pid=2425 port=27017
    dbpath=/data/db/ 64-bit host=spock
Thu Oct 11 12:36:48 [initandlisten] db version v2.4.0, pdfile version 4.5
Thu Oct 11 12:36:48 [initandlisten] git version:
    3aaea5262d761e0bb6bfef5351cfbfca7af06ec2
Thu Oct 11 12:36:48 [initandlisten] build info: Darwin spock 11.2.0 Darwin Kernel
    Version 11.2.0: Tue Aug 9 20:54:00 PDT 2011;
    root:xnu-1699.24.8~1/RELEASE_X86_64 x86_64 BOOST_LIB_VERSION=1_48
Thu Oct 11 12:36:48 [initandlisten] options: {}
Thu Oct 11 12:36:48 [initandlisten] journal dir=/data/db/journal
Thu Oct 11 12:36:48 [initandlisten] recover : no journal files present, no
    recovery needed
Thu Oct 11 12:36:48 [websvr] admin web console waiting for connections on
    port 28017
Thu Oct 11 12:36:48 [initandlisten] waiting for connections on port 27017

在Windows系統中,執行這個命令:

$ mongod.exe

mongod在沒有參數的狀況下會使用默認數據目錄/data/db(Windows系統中爲C:datadb)。若是數據目錄不存在或者不可寫,服務器會啓動失敗。所以,在啓動MongoDB前,先建立數據目錄(如mkdir -p /data/db/),以確保對該目錄有寫權限,這點很是重要。

sudo mkdir -p /data/db/
sudo chmod -R 777 /data/db

啓動時,服務器會打印版本和系統信息,而後等待鏈接。默認狀況下,MongoDB監聽27017端口。若是端口被佔用,啓動將失敗。一般,這是因爲已經有一個MongoDB實例在運行了。
mongod還會啓動一個很是基本的HTTP服務器,監聽數字比主端口號高1000的端口,也就是28017端口。這意味着,經過瀏覽器訪問http://localhost:28017,能獲取數據庫的管理信息。
停止mongod的運行,只須在運行着服務器的shell中按下Ctrl-C。

2.5 MongoDB shell簡介

MongoDB自帶JavaScript shell,可在shell中使用命令行與MongoDB實例交互。shell很是有用,經過它能夠執行管理操做,檢查運行實例,亦或作其餘嘗試。對MongoDB來講,mongo shell是相當重要的工具,其應用之普遍將體如今本書接下來的部分中。

2.5.1 運行shell

運行mongo啓動shell:

$ mongo
MongoDB shell version: 2.4.0
connecting to: test

啓動時,shell將自動鏈接MongoDB服務器,須確保mongod已啓動。
shell是一個功能完備的JavaScript解釋器,可運行任意JavaScript程序。爲說明這一點,咱們運行幾個簡單的數學運算:

> x = 200
200
> x / 5;
40

另外,可充分利用JavaScript的標準庫:

> Math.sin(Math.PI / 2);
1
> new Date("2010/1/1");
"Fri Jan 01 2010 00:00:00 GMT-0500 (EST)"
> "Hello, World!".replace("World", "MongoDB");
Hello, MongoDB!
再者,可定義和調用JavaScript函數:
> function factorial (n) {
... if (n <= 1) return 1;
... return n * factorial(n - 1);
... }
> factorial(5);
120

須要注意,可以使用多行命令。shell會檢測輸入的JavaScript語句是否完整,如沒寫完可在下一行接着寫。在某行連續三次按下回車鍵可取消未輸入完成的命令,並退回到>-提示符。

2.5.2 MongoDB客戶端

能運行任意JavaScript程序聽上去很酷,不過shell的真正強大之處在於,它是一個獨立的MongoDB客戶端。啓動時,shell會連到MongoDB服務器的test數據庫,並將數據庫鏈接賦值給全局變量db。這個變量是經過shell訪問MongoDB的主要入口點。
若是想要查看db當前指向哪一個數據庫,可使用db命令:

> db
test

爲了方便習慣使用SQL shell的用戶,shell還包含一些非JavaScript語法的擴展。這些擴展並不提供額外的功能,而是一些很是棒的語法糖。例如,最重要的操做之一爲選擇數據庫:

> use foobar
switched to db foobar

如今,若是查看db變量,會發現其正指向foobar數據庫:

> db
foobar

由於這是一個JavaScript shell,因此鍵入一個變量會將此變量的值轉換爲字符串(即數據庫名)並打印出來。
經過db變量,可訪問其中的集合。例如,經過db.baz可返回當前數據庫的baz集合。由於經過shell可訪問集合,這意味着,幾乎全部數據庫操做均可以經過shell完成。

2.5.3 shell中的基本操做

在shell中查看或操做數據會用到4個基本操做:建立、讀取、更新和刪除(即一般所說的CRUD操做)。

1. 建立

insert函數可將一個文檔添加到集合中。舉一個存儲博客文章的例子。首先,建立一個名爲post的局部變量,這是一個JavaScript對象,用於表示咱們的文檔。它會有幾個鍵:"title"、"content"和"date"(發佈日期)。

> post = {"title" : "My Blog Post",
... "content" : "Here's my blog post.",
... "date" : new Date()}
{
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2012-08-24T21:12:09.982Z")
}

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

> db.blog.insert(post)

這篇文章已被存到數據庫中。要查看它可用調用集合的find方法:

> db.blog.find()
{
    "_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2012-08-24T21:12:09.982Z")
}

能夠看到,咱們曾輸入的鍵/值對都已被完整地記錄。此外,還有一個額外添加的鍵"_id"。"_id"忽然出現的緣由將在本章末尾解釋。

2. 讀取

find和findOne方法能夠用於查詢集合裏的文檔。若只想查看一個文檔,可用findOne:

> db.blog.findOne()
{
    "_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2012-08-24T21:12:09.982Z")
}

find和findOne能夠接受一個查詢文檔做爲限定條件。這樣就能夠查詢符合必定條件的文檔。使用find時,shell會自動顯示最多20個匹配的文檔,也可獲取更多文檔。第4章會詳細介紹查詢相關的內容。

3. 更新

使用update修改博客文章。update接受(至少)兩個參數:第一個是限定條件(用於匹配待更新的文檔),第二個是新的文檔。假設咱們要爲先前寫的文章增長評論功能,就須要增長一個新的鍵,用於保存評論數組。
首先,修改變量post,增長"comments"鍵:

> post.comments = []
[ ]

而後執行update操做,用新版本的文檔替換標題爲「My Blog Post」的文章:

> db.blog.update({title : "My Blog Post"}, post)

如今,文檔已經有了"comments"鍵。再用find查看一下,能夠看到新的鍵:

> db.blog.find()
{
    "_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
    "title" : "My Blog Post",
    "content" : "Here's my blog post.",
    "date" : ISODate("2012-08-24T21:12:09.982Z"),
    "comments" : [ ]
}

4. 刪除

使用remove方法可將文檔從數據庫中永久刪除。若是沒有使用任何參數,它會將集合內的全部文檔所有刪除。它能夠接受一個做爲限定條件的文檔做爲參數。例如,下面的命令會刪除剛剛建立的文章:

> db.blog.remove({title : "My Blog Post"})

如今,集合又是空的了。

上一篇文章: MongoDB指南---一、MongoDB簡介
下一篇文章: MongoDB指南---三、MongoDB基礎知識-數據類型
相關文章
相關標籤/搜索