mysqlobjectid_MongoDBObjectId详解及使⽤
MongoDB中我们经常会接触到⼀个⾃动⽣成的字段:”_id”,类型为ObjectId。
本⽂详解ObjectId的构成和使⽤。
ObjectId构成
之前我们使⽤MySQL等关系型数据库时,主键都是设置成⾃增的。但在分布式环境下,这种⽅法就不可⾏了,会产⽣冲突。为
此,MongoDB采⽤了⼀个称之为ObjectId的类型来做主键。ObjectId是⼀个12字节的  BSON 类型字符串。按照字节顺序,⼀次代表:
4字节:UNIX时间戳
3字节:表⽰运⾏MongoDB的机器
2字节:表⽰⽣成此_id的进程
3字节:由⼀个随机数开始的计数器⽣成的值
ObjectId获取时间
从ObjectId的构造上来看,内部就嵌⼊了时间类型。我们肯定可以从中获取时间信息:即插⼊此⽂档时的时间。MongoDB对ObjectId对象提供了getTimestamp()⽅法来获取ObjectId的时间。
> a = new ObjectId()ObjectId("53102b43bf1044ed8b0ba36b")> a.getTimestamp()ISODate("2014-02-28T06:22:59Z")
根据时间构造ObjectId
上例是直接使⽤MongoDB提供的新建⽅法来构造ObjectId的,我们⾃⼰可不可以通过字符串来构造呢?看下例:// 使⽤Date的字符串构造⽅法⽣成⽇期,然后使⽤Date对象的getTime获取毫秒数,再除以1000得到标准时间戳> a = new Date("2012-12-
12 00:00:00").getTime()/10001355241600// 获取时间戳的标准⼗六进制表⽰ > a = a.toString(16)
50c75880// 在后⾯填补16个0 > a = a + new Array(17).join("0") 50c758800000000000000000// 使⽤24个字符串构造ObjectId > b = new ObjectId(a) ObjectId("50c758800000000000000000")// 获取时间以验
证 > b.getTimestamp() ISODate("2012-12-11T16:00:00Z")
上述过程中 new Array(17).join(“0″)⽬的是⽣成16个0拼接的字符串。
这⾥使⽤了点⼩技巧。new Array(17)构造了⼀个17个元素的数组,但是数组⾥⾯没有元素,join(atr)⽅法的作⽤是连接数组元素并且以其参数分割。17个元素正好有16个间隔,所以最终拼接起来的字符串为16个。
根据ObjectId按照插⼊时间排序
MongoDB默认在ObjectId上建⽴索引,是按照插⼊时间排序的。我们可以使⽤此索引进⾏查询和排序。// 按序插⼊三个⽂档
> db.col.insert({"num":1})
> db.col.insert({"num":2})
mongodb和mysql结合> db.col.insert({"num":3})
> db.col.find().pretty()
{ "_id" : ObjectId("53102fb4bf1044ed8b0ba36c"), "num" : 1 }
{ "_id" : ObjectId("53102fb9bf1044ed8b0ba36d"), "num" : 2 }
{ "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }
Q&A
为什么选择ObjectId
⽽不是递增ID?参考segmentfault上⾯的问题:mongoDB修改”_id”的objectID到普通递增id为什么不好
如何取到ObjectId⾥⾯的时间?
shell下可直接Timestamp()。各种驱动也都有对应的⽅法。
如何使⽤⽇期范围来查询ObjectId?
既然ObjectId是可以排序的,它当然也可以⽐较⼤⼩。在有⽇期范围的情况下,实际上可以从_id中利⽤IXSCAN到相应的记录,⽽不需要根据另外⼀个时间字段来查询。如果时间字段正好没有索引的话,_id的优势就体现出来了。stackoverflow上详细讲了该怎么做。
使⽤⾃⼰⽣成的UUID字符串和ObjectId⽐较哪个做_id更好?
作者:陈光剑

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。