mongodb 的 ObjectId

2017/07/18

官方文档解释

ObjectId(<hexadecimal>)

这是一个 12 字节(12-byte)的 ObjectId,其中包括:

可选参数:

Field Type Description
hexadecimal String 可选,16 进制字符串

ObjectId() 有以下属性和方法:

Attribute/Method Description
str 返回这个 id 的 16 进制表示的字符串
ObjectId.getTimestamp() 返回这个 id 编码的时间戳
ObjectId.toString() 返回字符串: ObjectId(...)
ObjectId.valueOf() 就是 属性 str返回的那个,一样的

解释一个真实的 id

596cee8fd68096396dc0390b

时间戳

一个秒级的时间戳是 10 位十进制数的,如果采用无符号表示方法,那么 n 位二进制(n 个 bit)可以表示的最大数字是 2^n-1,现在需要表示秒级时间戳,就需要 m bit 的空间,也就是:

$$2^m - 1 >= 10^9$$ $$m >= log_{2}^(10^9 + 1)$$ $$m >= 29.8974$$

不过注意哈,objectid 是用 16 进制表示的,我们知道 4 位二进制对应于 1 位 16 进制,所以要么是 8 位(对应于 32 位二进制),满足 $$m >= 29.8974$$ 要么是 7 位 16 进制(对应于 28 位二进制),不满足 $$m >= 29.8974$$ 所以很显然,m 取 32,也就是说用 8 位 16 进制字符串(32bit)表示一个时间戳 这个在定义中就明确了:4字节的unix秒级时间戳,即 32bit

分割 ObjectId

596cee8fd68096396dc0390b => 596cee8f  d68096  396d  c0390b

596cee8f是 16 进制时间戳,转化为 10 进制: sadf d68096是机器代码,不会变 396d是进程代码,不会变 c0390b是计数器,从随机数开始增加

创建 ObjectId

可以看到,数据符合我们的预期,中间两个代码没有变,前面的增加的是秒数,后面的是计数器(+1)

引用