_id key举例说明 :
当我们在往一个collection中写入一条记录时,系统会自动生成一个名为_id 的key.如:
> db.userinfo.insert({"username":"digoal","age":27})
> db.userinfo.findOne()
{
"_id" : ObjectId("4d1952479581fcf2f449f55e"),
"username" : "digoal",
"age" : 27
}
这里多出了一个类型为ObjectId的key ,在插入时并没有指定对吧,有点类似ORACLE的ROWID的信息。
在mongoDB中,每一个collection都必须有一个叫做_id的字段,字段类型默认是ObjectId ,换句话说,字段类型可以不是ObjectId,例如:
> db.userinfo.insert({"_id":1,"username":"digoal","age":27})
> db.userinfo.find()
{ "_id" : ObjectId("4d1952479581fcf2f449f55e"), "username" : "digoal", "age" : 27 }
{ "_id" : 1, "username" : "digoal", "age" : 27 }
虽然_id的类型可以自由指定,但是在同一个collection中必须唯一。如下:
> db.userinfo.insert({"_id":1,"username":"digoal","age":27})
E11000 duplicate key error index: test.userinfo.$_id_ dup key: { : 1.0 }
因为前面已经插入了一条_id=1的记录,所以再插就不允许了 。
ObjectId 类型举例说明 :
ObjectId是_id的默认类型前面已经提到过,下面我们来看看几个要素:
1. _id在一个collection中必须是唯一的,
2. 一般的程序设计理念是将运算推送到客户端,而不是服务端或数据库,
要满足第一点的话,ObjectId的产生必须是唯一的,ObjectId由12个字节组成,我们来看看ObjectId的结构:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
0-3表示timestamp
4-6表示machine
7-8表示PID
9-11表示increment
下面来详细的解释一下:
timestamp分片 : 表述自 1970 -01-01T00:00:00Z以来的经过秒数.由于将timestamp放在整个KEY的前面四个字节,所以插入顺序和_id的顺序基本匹配,使用timestamp还有一个好处是,某些客户端驱动可以通过ObjectId解析出该记录是何时插入的。
machine分片 : 表述产生这个ObjectId的主机的主机名(通常是主机名)的hash值,因此不同的主机将产生不同的HASH值。
PID分片 : 表述产生这个ObjectId的进程的进程号,因此在同一个主机中不同的进程产生的ObjectId值也是不一样的。
前面9个字节的值确保了在同一秒不同的主机不同的进程产生的ObjectId是唯一的。
increment分片 : 为了确保同一台主机同一个进程在同一秒内产生的ObjectId唯一,最后三个字节是一个自增长的值,允许256的3次方等于16777216条记录的唯一性。
虽然mongodb的sharding很好很强大,但是产生ObjectId也会有一定的服务器资源开销,所以遵循一般的程序设计理念,将运算推送到客户端,而不是在服务端或数据库。
因此大多数mongodb的客户端驱动都支持ObjectId的生成,而ObjectId这个类型也很好的支持了全局的唯一性.