·文檔是Mongodb中數據的基本單元,非常類似於關係型數據庫管理系統中的行,但更具有表現力。
·集合(collection)可以看作是一個擁有動態模式(dynamic schema)的表。
·Mongodb的一個實例可以擁有多個相互獨立的數據庫(database),每個數據庫都擁有自己的集合。
·每一個文檔都擁有一個特殊的鍵“_id”,這個鍵在文檔所屬的集合中是唯一的。
·Mongodb自帶了一個簡單但功能強大的JavaScript Shell,可以用於管理Mongodb的實例或數據庫操作。
1. 文檔
文檔是Mongodb的核心概念。文檔就是鍵值對的一個有序集。
文檔的鍵是字符串,除了少數例外情況,鍵可以使用任意UTF-8字符。
鍵不能含有\0(空字符)。這個字符用於表示鍵的結尾。
.和$具有特殊意義,只能在特定環境下使用。
Mongodb文檔不能有重複的鍵。
2.集合
集合就是一組文檔。
集合是動態模式的。這意味着一個集合裏面的文檔可以是各式各樣的。
思考:因爲集合裏面可以放置任何文檔,那麼有必要使用多個集合嗎?
·如果把各種各樣的文檔不加區分地放在同一個集合裏,無論對開發者還是對管理員來說都將是噩夢。
·在一個集合裏查詢特定類型的文檔在速度上也很不划算,分開查詢多個集合要快得多。
·把同種類型的文檔放在一個集合裏,數據會更加集中。
·創建索引時,需要使用文檔的附加結構(特別是創建唯一索引時)。索引是按照集合來定義的。在一個集合中只放入一種類型的文檔,可以更有效的對集合進行索引。
集合命名:
·集合名不能是空字符串("")。
·集合名不能包含\0字符(空字符)。這個字符表示集合名的結束。
·集合名不能以“system.”開頭,這是爲系統集合保留的前綴。
·創建的集合不能包含保留字符“$”。
子集合:組織集合的一種慣例是使用"."分隔不同命名空間的子集合。(例如:blog.posts、blog.authors)
3.數據庫
在Mongodb中,多個文檔組成集合,而多個集合可以組成數據庫。
數據庫通過名稱來標識,這點與集合類似。
·不能是空字符串。
·不得含有(/ \ . " < > : | > $ \0 …)。基本上只能使用ASCII中的字母和數字。
·數據庫名區分大小寫。
·數據庫名最多爲64字節。
保留數據庫名:admin、local、config
命名空間(namespace):是把數據庫名添加到集合名前,得到的集合完全限定名。(如:cms數據庫的blog.posts集合,這個集合的命名空間是cms.blog.posts。)
命名空間的長度不得超過121字節,且在實際使用中應小於100字節。
4.啓動數據庫
默認情況下,Mongodb監聽27017端口。mongod還會啓動一個非常基本的HTTP服務器,監聽數字比主端口號高1000的端口,默認是28017端口。
5.Mongodb Shell簡介
Mongodb自帶JavaScript Shell,可在Shell中使用命令行與Mongodb實例交互。它是一個獨立的Mongodb客戶端,通過運行mongo啓動Shell時,會連接到Mongodb數據庫服務器的test數據庫。
使用db命令可以查看當前所在數據庫!
在Shell中查看或操作數據會用到4個基本操作:創建、讀取、更新和刪除(CRUD操作)。
創建:insert函數
可以將一個文檔添加到集合中。
下圖爲存儲博客文章的例子,首先創建一個名爲post的局部變量,這是一個JavaScript對象,用於表示我們的文檔。
然後可以用insert方法將其保存到blog集合中。
讀取:find和findOne方法
可以用於查詢集合裏的文檔。若只查詢一個文檔用findOne,使用find時,Shell會自動顯示最多20個匹配的文檔,也可以獲取更多。
更新:update
接受(至少)兩個參數:第一個是限定條件(用於匹配待更新的文檔),第二個是新的文檔。
假設我們要爲先前寫的文章增加評論功能,就需要增加一個新的鍵,用於保存評論數組。
首先修改變量post,增加"comments"鍵,然後執行update操作,用新版本的文檔替換標題爲"My blog post"的文章:
刪除:remove
使用remove方法可以將文檔從數據庫中永久刪除。如果沒有使用任何參數,它會將集合內的所有文檔全部刪除。它可以接受一個作爲限定條件的文檔作爲參數。例如下面的命令刪除上面創建的文檔:
>db.blog.remove({title : "My blog post"})
6.數據類型
基本數據類型:
在概念上,Mongodb的文檔與JavaScript中的對象相近,因而可認爲它類似於JSON。
·null:用於表示空值或者不存在的字段。 {"x" : null}
·布爾型:有兩個值true和false。 {"x" : true}
·數值:Shell默認使用64位浮點型數值。因此,以下數值在Shell中是很“正常”的: {"x" : 3.14} 或 {"x" : 3}
對於整型值,可使用NumberInt類(表示4字節帶符號整數)或NumberLong類(表示8字符帶符號整數),分別舉例如下:
{"x" : NumberInt("3")} {"x" : NumberLong("3")}
·字符串:UTF-8字符串都可表示爲字符串類型的數據。 {"x" : "foobar"}
·日期:被存儲爲自新紀元以來經過的毫秒數,不存儲時區。 {"x" : new Date()}
·正則表達式:查詢時,使用正則表達式作爲限定條件,語法與JavaScript的正則表達式語法相同。 {"x" : /foobar/i}
·數組:數據列表或數據集可以表示爲數組。 { "x" : ["a","b","c"]}
·內嵌文檔:文檔可嵌套其它文檔,被嵌套的文檔作爲父文檔的值。 {"x" : {"foo" : "bar"}}
·對象id:是一個12字節的ID,是文檔的唯一標識。 {"x" : ObjectId()}
_id和ObjectId:
MongoDB 中存儲的文檔必須有一個"_id" 鍵。這個鍵的值可以是任何類型的,默認是個ObjectId 對象。在一個集合裏面,每個文檔都有唯一的"_id" 值,來確保集合裏面每個文檔都能被唯一標識。如果有兩個集合的話,兩個集合可以都有一個值爲123 的"_id" 鍵,但是每個集合裏面只能有一個"_id" 是123 的文檔。
①.ObjectId
ObjectId 是"_id" 的默認類型。它設計成輕量型的,不同的機器都能用全局唯一的同種方法方便地生成它。這是MongoDB 採用ObjectId,而不是其他比較常規的做法(比如自動增加的主鍵)的主要原因,因爲在多個服務器上同步自動增加主鍵值既費力還費時。MongoDB 從一開始就設計用來作爲分佈式數據庫,處理多個節點是一個核心要求。後面會看到ObjectId 類型在分片環境中要容易生成得多。
ObjectId 使用12 字節的存儲空間,每個字節兩位十六進制數字,是一個24 位的字符串。由於看起來很長,不少人會覺得難以處理。但關鍵是要知道這個長長的ObjectId 是實際存儲數據的兩倍長。
如果快速連續創建多個ObjectId,會發現每次只有最後幾位數字有變化。另外,中間的幾位數字也會變化(要是在創建的過程中停頓幾秒鐘)。這是ObjectId 的創建方式導致的。12 字節按照如下方式生成:
前4 個字節是從標準紀元開始的時間戳,單位爲秒。這會帶來一些有用的屬性。
·時間戳,與隨後的. 5 個字節組合起來,提供了秒級別的唯一性。
·由於時間戳在前,這意味着ObjectId 大致會按照插入的順序排列。這對於某些方面很有用,如將其作爲索引提高效率,但是這個是沒有保證的,僅僅是“大致”。
·這4 個字節也隱含了文檔創建的時間。絕大多數驅動都會公開一個方法從ObjectId 獲取這個信息。
因爲使用的是當前時間,很多用戶擔心要對服務器進行時間同步。其實沒有這個必要,因爲時間戳的實際值並不重要,只要其總是不停增加就好了(每秒一次)。
接下來的3 字節是所在主機的唯一標識符。通常是機器主機名的散列值。這樣就可以確保不同主機生成不同的ObjectId,不產生衝突。
爲了確保在同一臺機器上併發的多個進程產生的ObjectId 是唯一的,接下來的兩字節來自產生ObjectId 的進程標識符(PID)。
前9 字節保證了同一秒鐘不同機器不同進程產生的ObjectId 是唯一的。後3 字節就是一個自動增加的計數器,確保相同進程同一秒產生的ObjectId 也是不一樣的。同一秒鐘最多允許每個進程擁有2563(16 777 216)個不同的ObjectId。
②.自動生成_id
前面講到,如果插入文檔的時候沒有"_id" 鍵,系統會自動幫你創建一個。可以由MongoDB 服務器來做這件事情,但通常會在客戶端由驅動程序完成。理由如下。
雖然ObjectId 設計成輕量型的,易於生成,但是畢竟生成的時候還是產生開銷。在客戶端生成體現了MongoDB 的設計理念:能從服務器端轉移到驅動程序來做的事,就儘量轉移。這種理念背後的原因是,即便是像MongoDB 這樣的可擴展數據庫,擴展應用層也要比擴展數據庫層容易得多。將事務交由客戶端來處理,就減輕了數據庫擴展的負擔。
在客戶端生成ObjectId,驅動程序能夠提供更加豐富的API。例如,驅動程序可以有自己的insert 方法,可以返回生成的ObjectId,也可以直接將其插入文檔。如果驅動程序允許服務器生成ObjectId,那麼將需要單獨的查詢,以確定插入的文檔中的"_id" 值。
PS:內容整理於《Mongodb權威指南》