mongodb指南(翻译)(十三) - developer zone - 数据类型和约定(二)之Object ID
Object IDs
在mongodb中的文档需要使用唯一的关键字_id来标识他们。
_id字段
几乎每一个mongodb文档都使用_id字段作为第一个属性(在系统集合和定容量集合(capped collection)中有一些例外)。_id值可以是任何类型,最常见的做法是使用ObjectId类型。每一个文档的_id字段在该集合中必须是唯一的;这是由于集合会自动为_id建立索引而强制要求的(除了前面提到的那些例外)。
如果用户尝试插入一个不带_id字段的文档,数据库会自动生成一个对象id并保存在_id字段。
_id值可以是任何类型,只要它是唯一的,但除了数组。如果你的文档有一个天然独有的不可更改的主键,我们推荐你使用它代替自动生成的_id。数组不允许作为_id,是因为他们是多键的。
BSON ObjectId 数据类型
虽然_id值可以是任何类型,但是mongodb依然为对象id提供了一个特殊的BSON数据类型。该类型设计为12个字节的二进制值,这样就具有相当高的概率保证分配时的唯一性。所有官方支持的mongodb驱动都默认使用该类型作为_id的值。同时,mongo数据库自身在插入无_id字段的文档时,也使用这个类型给_id赋值。
在mongodb shell,ObjectId()可以在用来传教ObjectIds.ObjectId(String)使用指定的16进制字符串创建对象ID。
> x={ name: "joe" }
{ name : "joe" }
> db.people.save(x)
{ name : "joe" , _id : ObjectId( "47cc67093475061e3d95369d" ) }
> x
{ name : "joe" , _id : ObjectId( "47cc67093475061e3d95369d" ) }
> db.people.findOne( { _id: ObjectId( "47cc67093475061e3d95369d" ) } )
{ _id : ObjectId( "47cc67093475061e3d95369d" ) , name : "joe" }
> db.people.findOne( { _id: new ObjectId( "47cc67093475061e3d95369d" ) } )
{ _id : ObjectId( "47cc67093475061e3d95369d" ) , name : "joe" }
BSON ObjectID 详细说明
一个BSON ObjectID是12字节的值,包含了4字节的时间戳(纪元以来的秒数),3字节机器id,2字节进程id,和3字节计数值。注意不同于BSON中的其他字段,时间戳和计数值字段必须存储为big endian。这是由于会对它们按字节比较,我们希望大多数情况下保证是升序。它的格式:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
time | machine | pid | inc |
- TimeStamp.这是一个unix风格的时间戳。它是有符号整数,代表自1970年1月1日之后或者之前的秒数。
- Machine。它是机器主机名hash(md5)后值,或者mac/network 地址,或者虚拟机id的前三个字节。
- pid。它是进程生成的2字节的进程id(或线程id)。
- increment。这是一个自增值,或者在当前语言/运行时不能使用计数器时的随机值。
BSON ObjectIds可以是任意唯一的12字节二进制字符串;但是,服务器本身和绝大多数驱动都使用了上面的格式。
顺序号
传统的数据库经常使用递增的顺序号作为主键。在MongoDB中,较好的方法是使用Object IDs。这个概念是说在一个非常大的集群中,创建一个Object ID比维护全局的,单调增长的顺序号要容易的多。
尽管如此,有些时候你还是需要一个顺序号。你可以通过创建"counter"文档和使用findAndModify命令来达到这一目的。
function counter(name) {
var ret = db.counters.findAndModify({query:{_id:name}, update:{$inc : {next:1}}, "new":true,
upsert:true});
// ret == { "_id" : "users", "next" : 1 }
return ret.next;
}
db.users.insert({_id:counter("users"), name:"Sarah C."}) // _id : 1
db.users.insert({_id:counter("users"), name:"Bob D."}) // _id : 2
//repeat
UUIDs
_id字段可以是任意类型;但是必须是唯一的。这样的话你就可以在_id字段使用UUIDs来代替BSON ObjectIds(BSON ObjectIds要轻巧一些;它们不需要全球唯一,仅仅在当前数据库集群唯一就可以了).当使用UUIDs,你的应用程序要自己生成UUID.考虑到效率,将UUID存储为[DOCS:BSON]类型是理想的 - 无论如何你还是可以将它作为16进制字符串插入,如果你知道空间和速度在此时不是一个问题。
posted on 2011-12-13 17:02 xinghebuluo 阅读(2124) 评论(0) 编辑 收藏 举报