_id和ObjectId
MongoDB中儲存的文檔必須有一個"_id"鍵。這個鍵的值可以是任何類型的,預設是個ObjectId對象。
在一個集合裡面,每個集合都有唯一的"_id"值,來確保集合裡面每個文檔都能被唯一標識。如果有
兩個集合的話,兩個集合可以都有一個值為"123"的"_id"的鍵,但是每個集合裡面只能有一個"_id"
是123的文檔。
1.ObjectId
ObjectId是"_id"的預設類型。它設計成輕量型的,不同的機器都能用全域唯一的同種方法方便地產生它。
這是MongoDB採用ObjectId,而不是其他比較常規的做法(比如自動增加的主鍵)的主要原因,因為在多個
伺服器上同步自動增加主鍵值既費力還費時。MongoDB從一開始就設計用來作為分散式資料庫,處理多個節
點是一個核心要求。後面會講到ObjectId類型在分區環境中容易產生得多。
ObjectId使用12位元組的儲存空間,每個位元組兩位十六進位數字,是一個24位的字串。由於看起來很長,不
少人會覺得難以處理。但關鍵是要知道這個長長的ObjectId是實際儲存資料的兩倍長。
如果快速連續建立多個ObjectId,會發現每次只有最後幾位元字有變化。另外中間的幾位元字也會變化(要
是在建立的過程中停頓幾秒鐘)。這是ObjectId的建立方式導致的。12位元組按照如下方式產生:
0|1|2|3|4|5|6|7|8|9|10|11
時間戳記|機器 |PID|計數器
前4位元組是從標準紀元開始的時間戳記,單位為秒。這會帶來一些有用的屬性。
時間戳記,與隨後的5個位元組組合起來,提供了秒層級的唯一性。
由於時間戳記在前,這意味著ObjectId大致會按照插入的順序排列。這對於某些方面很有用,如將其作為索引提
高效率,但是這個是沒有保證的,僅僅是"大致"。這4個位元組也隱含了文檔建立的時間。絕大多數驅動都會公開
一個方法從ObjectId擷取這個資訊。
因為使用的是目前時間,很多使用者擔心要對伺服器進行時間同步,其實這個沒有必要,因為時間戳記的實際值並不
重要,只要其總是不停增加就好了(每秒一次)。
接下來的三個位元組是所在主機的唯一識別碼。通常是機器主機名稱的散列值。這樣就可以確保不同主機產生不同的
ObjectId,不產生衝突。
為了確保在同一台機器上並發的多個進程產生的ObjectId是唯一的。後3個位元組就是一個自動增加的計數器,確
保相同進程同一秒產生的ObjectId也是不一樣的。同一秒鐘最多允許每個進程擁有256(16777216)個不同的ObjectId。
2.自動產生_id
前面講到,如果插入文檔的時候沒有"_id"鍵,系統會幫你自動建立一個。可以由MongoDB伺服器來做這件事情,但
通常會在用戶端由驅動程式完成。理由如下:
雖然ObjectId設計成輕量型的,易於產生,但是畢竟產生的時候還是產生開銷。在用戶端產生體現了MongoDB的設計
理念:能從伺服器端轉移到驅動程式來做的事,就盡量轉移。這種理念背後的原因是,即便是像MongoDB這樣的可擴
展資料庫,擴充應用程式層也要比擴充資料庫層容易的多。將事務交由用戶端來處理,就減輕了資料庫擴充的負擔。
在用戶端產生ObjectId,驅動程式能夠提供更加豐富的API。例如,驅動程式可以有自己的insert方法,可以返回生
成的ObjectId,也可以直接將其插入文檔。如果驅動程式允許伺服器產生ObjectId,那麼將需要單獨的查詢,以確
定插入的文檔中的"_id"值。