# 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")
```