2017年09月13日 14:25:18 universsky2015 閱讀數:11802mongodb
版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/universsky2015/article/details/77965374shell
MongoDB中咱們常常會接觸到一個自動生成的字段:」_id」,類型爲ObjectId。
本文詳解ObjectId的構成和使用。數據庫
以前咱們使用MySQL等關係型數據庫時,主鍵都是設置成自增的。但在分佈式環境下,這種方法就不可行了,會產生衝突。爲此,MongoDB採用了一個稱之爲ObjectId的類型來作主鍵。ObjectId是一個12字節的 BSON 類型字符串。按照字節順序,一次表明:segmentfault
4字節:UNIX時間戳
3字節:表示運行MongoDB的機器
2字節:表示生成此_id的進程
3字節:由一個隨機數開始的計數器生成的值數組
從ObjectId的構造上來看,內部就嵌入了時間類型。咱們確定能夠從中獲取時間信息:即插入此文檔時的時間。MongoDB對ObjectId對象提供了getTimestamp()方法來獲取ObjectId的時間。分佈式
> a = new ObjectId()ObjectId("53102b43bf1044ed8b0ba36b")> a.getTimestamp()ISODate("2014-02-28T06:22:59Z")
上例是直接使用MongoDB提供的新建方法來構造ObjectId的,咱們本身可不能夠經過字符串來構造呢?看下例:spa
// 使用Date的字符串構造方法生成日期,而後使用Date對象的getTime獲取毫秒數,再除以1000獲得標準時間戳
.net
> a = new Date("2012-12-12 00:00:00").getTime()/1000
code
1355241600
對象
// 獲取時間戳的標準十六進制表示
> a = a.toString(16)
50c75880
// 在後面填補16個0
> a = a + new Array(17).join("0") 50c758800000000000000000// 使用24個字符串構造ObjectId
> b = new ObjectId(a) ObjectId("50c758800000000000000000")// 獲取時間以驗證
> b.getTimestamp() ISODate("2012-12-11T16:00:00Z")
上述過程當中 new Array(17).join(「0″)目的是生成16個0拼接的字符串。
這裏使用了點小技巧。new Array(17)構造了一個17個元素的數組,可是數組裏面沒有元素,join(atr)方法的做用是鏈接數組元素而且以其參數分割。17個元素正好有16個間隔,因此最終拼接起來的字符串爲16個。
根據ObjectId按照插入時間排序
MongoDB默認在ObjectId上創建索引,是按照插入時間排序的。咱們可使用此索引進行查詢和排序。
// 按序插入三個文檔
> db.col.insert({"num":1})
> db.col.insert({"num":2})
> db.col.insert({"num":3})
> db.col.find().pretty()
{ "_id" : ObjectId("53102fb4bf1044ed8b0ba36c"), "num" : 1 }
{ "_id" : ObjectId("53102fb9bf1044ed8b0ba36d"), "num" : 2 }
{ "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }
爲何選擇ObjectId
而不是遞增ID?參考segmentfault上面的問題:mongoDB修改」_id」的objectID到普通遞增id爲何很差
如何取到ObjectId裏面的時間?
shell下可直接oid.getTimestamp()。各類驅動也都有對應的方法。
如何使用日期範圍來查詢ObjectId?
既然ObjectId是能夠排序的,它固然也能夠比較大小。在有日期範圍的狀況下,實際上能夠從_id中利用IXSCAN找到相應的記錄,而不須要根據另一個時間字段來查詢。若是時間字段正好沒有索引的話,_id的優點就體現出來了。stackoverflow上詳細講了該怎麼作。
使用本身生成的UUID字符串和ObjectId比較哪一個作_id更好?
中籤王言:抓住新股申購黃金時間點,10打新10次中,屢試不爽