ObjectId使用12字节的存储空间,是一个由24个16进制数字组成的字符串(每个字节可以存储两个16进制数字)。
说明:
12字节(每个字节用2个16位的组成),
因此,总共24个16位的数字。
1:如果快速的连续创建多个ObjectId,会发现每次只有最后几位数字有变化。
另外,中间的几位数字也会变化(要是在创建的过程中停顿几秒)
这是ObjectId的创建方式导致的。
2:ObjetId的12字节按照如下方式生成:
实际举例:
571094e2976aeb1df982ad4e
57 10 94 e2 97 6a eb 1d f9 82 ad 4e
ObjectId前4个字节是从标准纪元开始的时间戳,单位为秒。这会带来一些有用的属性。
2.1:时间戳,于随后的5字节(稍后介绍)组合起来,提供了秒级别的唯一性。
2.2:由于时间戳在前,这意味着ObjectId大致会按照插入的顺序排列。这对于某些方面很有用,
比如可以将其作为索引提高效率,但是这个是没有保证的,仅仅是“大致”。
2.3:这4个字节也隐含了文档的创建时间。绝大多数驱动程序都会提供一个方法,用于从ObjectId获取这些信息。
因为使用的是当前时间,很多用户担心要对服务器进行时钟同步。虽然在某些情况下,在服务器间进行时间同步
确实是个好主意,但是这里其实没有必要,因为时间戳的实际值并不重要,只要他总是不停增加就好了(每秒一次)。
--------------------------------------------
接下来的3个字节是所在主机的唯一标识符。
通常是机器主机名的散列值(hash)。
这样就可以确保不同主机生成不同的ObjectId,不产生冲突。
--------------------------------------------
为了确保在同一台机器上并发的多个进程产生的ObjectId是唯一的,接下来的2个字节来自产生ObjectId的进程的进程标识符(PID)。
--------------------------------------------
前9个字节保证了同一秒钟不同机器不同进程产生的ObjectId是唯一的。
最后3个字节是一个自动增加的计数器,确保相同进程同一秒产生的ObjectId也是不一样的。
一秒钟最多允许每个进程拥有256的3次方(16777216)个不同的ObjectId。
============================================================
因此在生产中我们可以根据id做一些事情:
1:按照_id升序《等价于》即按照插入时间升序
2:按照_id降序《等价于》即按照插入时间降序
为什么这么说呢?
因为前4位是一个unix的时间戳,是一个int类别,我们将上面的例子中的objectid的前4位进行提取“4df2dcec”,然后再将他们转为十进制:“1307761900”,这个数字就是一个时间戳,为了让效果更佳明显,我们将这个时间戳转换成我们习惯的时间格式( 精确到秒)
$ date -d '1970-01-01 UTC 1307761900 sec' -u
2011年 06月 11日 星期六 03:11:40 UTC
前 4个字节其实隐藏了文档创建的时间,并且时间戳处在于字符的最前面,这就意味着ObjectId大致会按照插入进行排序,这对于某些方面起到很大作用,如 作为索引提高搜索效率等等。使用时间戳还有一个好处是,某些客户端驱动可以通过ObjectId解析出该记录是何时插入的,这也解答了我们平时快速连续创 建多个Objectid时,会发现前几位数字很少发现变化的现实,因为使用的是当前时间,很多用户担心要对服务器进行时间同步,其实这个时间戳的真实值并 不重要,只要其总不停增加就好。
ObjectId("53102b43bf1044ed8b0ba36b").getTimestamp();
ISODate("2014-02-28T06:22:59Z");