# MongoDB 自動產生的唯一識別 ObjectId 在一開始接觸到 MongoDB 的時候發現自己塞了一筆資料進去都會看到有個 _id 的欄位出現,而且 value 看起來也不像是流水號,所以就再往裡面看了一點,想說了解一下它背後的一些知識點。 ## 介紹 在每個 collection 中都必須有個一定要 unique value 的欄位 **_id**,這個欄位可以是 string, number,只需要維持 unique 的條件即可。 以下是一份 MongoDB 中的 collection ```json { "_id": { "$oid": "56e9b39b732b6122f877fa31" }, "airline": { "id": { "$numberInt": "410" }, "name": "Aerocondor", "alias": "2B", "iata": "ARD" }, "src_airport": "CEK", "dst_airport": "KZN", "codeshare": "", "stops": { "$numberInt": "0" }, "airplane": "CR2" } ``` 在其中看到 **"$oid": "56e9b39b732b6122f877fa31"**,但其中的 data type 不是 string,而是 **ObjectId**。 當我們在 insert document 沒有指定 **_id** value 的時候就會自動產生一個類別為 ObjectId 的資料做使用,而這個 value 背後是依照什麼樣的規則去產生,又有什麼需要注意的事項? ## ObjectId 的組成 ObjectId("56e9b39b732b6122f877fa31") 是一個 12-byte 的資料,整份資料分成三個部分。 >- A 4-byte timestamp, representing the ObjectId's creation, measured in seconds since the Unix epoch. >- A 5-byte random value generated once per process. This random value is unique to the machine and process. > >- A 3-byte incrementing counter, initialized to a random value. 56e9b39b732b6122f877fa31 是一個 24字元 16 進制的字串,將它做拆解 | timestamp (4-byte) | random value (5-byte) | incrementing counter (3-byte) | | ------------------ | --------------------- | ----------------------------- | | 56e9b39b | 732b6122f8 | 77fa31 | ObjectId 的建構參數,有兩種選擇 1. ObjectId("56e9b39b732b6122f877fa31") 2. ObjectId(168) 這個稍微特別一點,如果帶入的是一個 integer,就會是上面看到 timestamp 的欄位資料,後面一樣會是自動產生,可能就會像是這樣。 ObjectId(168) => ObjectId("000000a8732b6122f877fa31") "000000a8" (Hex Number) => 168 (Decimal Number) ## 其他用途 既然前面有提到第一個部分是 timestamp,那就可以知道這筆資料的建立時間,但這邊還是要注意一下,如果希望資料是真的依照建立時間依序排列呈現,還是要額外建立 createdTime 的欄位來紀錄 timestamp 才是正確的,因為還有除了 timestamp 以外的因素可能會讓 _id 欄位的排序產生變化。 ```javascript ObjectId("56e9b39b732b6122f877fa31").getTimestamp() // ISODate("2016-03-16T19:27:23.000Z") ```