MongoDB:18-MongoDB-ObjectId

MongoDB中我们经常会接触到一个自动生成的字段:”_id”,类型为ObjectId。

ObjectId构成

   
  1. 之前我们使用MySQL等关系型数据库时,主键都是设置成自增的。
  2. 但在分布式环境下,这种方法就不可行了,会产生冲突。
  3. 为此,MongoDB采用了一个称之为ObjectId的类型来做主键。
  4. ObjectId是一个12字节的 BSON类型字符串。按照字节顺序,依次代表:

   
  1. 4字节:UNIX时间戳
  2. 3字节:机器识别码
  3. 2字节:表示生成此_id的进程
  4. 3字节:由一个随机数开始的计数器生成的值
  5.        
    1. 如:
    2.            
      1. 4df2dcec2cdcd20936a8b817

    3. TimeStamp
    4. 4位是一个unix的时间戳,是一个int类别,我们将上面中的objectid的前4位进行提取“4df2dcec”,
    5. 然后再将他们安装十六进制 专为十进制:“1307761900”,这个数字就是一个时间戳,为了让效果更佳明显,
    6. 我们将这个时间戳转换成我们习惯的时间格式(精确到秒)
    7.            
      1. $ date -d '1970-01-01 UTC 1307761900 sec' -u
      2. 2011 06 11 星期六 03:11:40 UTC

    8. 4个字节其实隐藏了文档创建的时间,并且时间戳处在于字符的最前面,
    9. 这就意味着ObjectId大致会按照插入进行排序,这对于某些方面起到很大作用, 作为索引提高搜索效率等等。
    10. 使用时间戳还有一个好处是,某些客户端驱动可以通过ObjectId解析出该记录是何时插入的,
    11. 这也解答了我们平时快速连续创 建多个Objectid时,会发现前几位数字很少发现变化的现实,
    12. 因为使用的是当前时间,很多用户担心要对服务器进行时间同步,其实这个时间戳的真实值并 不重要,只要其总不停增加就好。
    13. Machine
    14. 接下来的三个字节,就是 2cdcd2 ,这三个字节是所在主机的唯一标识符,一般是机器主机名的散列值,
    15. 这样就确保了不同主机生成不同的机器hash值,确保在分布式中不造成冲突,
    16. 这也就是在同一台机器生成的objectid中间的字符串都是一模一样的原因。
    17. pid
    18. 上面的Machine是为了确保在不同机器产生的objectid不冲突,
    19. pid就是为了在同一台机器不同的mongodb进程产生了objectid不冲突,接下来的0936两位就是产生objectid的进程标识符。
    20. increment
    21. 前面的九个字节是保证了一秒内不同机器不同进程生成objectid不冲突,这后面的三个字节a8b817
    22. 是一个自动增加的计数器,用来确保在同一秒内产生的objectid也不会发现冲突,允许2563次方等于16777216条记录的唯一性。

    
  1. MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。
  2. 在一个集合里面,每个文档都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。
  3. MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,
  4. 因为在多个 服务器上同步自动增加主键值既费力还费时。
     
  1. 补充:1个字节占多少个16进制位
  2. 1个字节是8位,最多表示0256
  3. 而一位16最多只表示到16,即F表示16,要表示到256,就还需要第二位,
  4. 所以1个字节占216进制位
  5. 一个16进制位占0.5个字节
创建新的ObjectId
      
  1. 使用以下代码生成新的ObjectId
  2. >newObjectId = ObjectId()
  3. 上面的语句返回以下唯一生成的id
  4. ObjectId("5349b4ddd2781d08c09890f3")
  5. 你也可以使用生成的id来取代MongoDB自动生成的ObjectId
  6. >myObjectId = ObjectId("5349b4ddd2781d08c09890f4")

创建文档的时间戳
    
  1. 由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,
  2. 你可以通过 getTimestamp 函数来获取文档的创建时间:
  3. >ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()
  4. 以上代码将返回 ISO 格式的文档创建时间:
  5. ISODate("2014-04-12T21:49:17Z")
根据时间构造 ObjectId
     
  1. // 使用Date的字符串构造方法生成日期
  2. // 然后使用Date对象的getTime获取毫秒数,再除以1000得到标准时间戳
  3. > a = new Date("2012-12-12 00:00:00").getTime()/1000
  4. 1355241600
  5. // 获取时间戳的标准十六进制表示
  6. > a = a.toString(16)
  7. 50c75880
  8. // 在后面填补16个0
  9. > a = a + new Array(17).join("0")
  10. 50c758800000000000000000
  11. // 使用24个字符串构造ObjectId
  12. > b = new ObjectId(a)
  13. ObjectId("50c758800000000000000000")
  14. // 获取时间以验证
  15. > b.getTimestamp()
  16. ISODate("2012-12-11T16:00:00Z")
      
  1. 上述过程中 new Array(17).join(“0″)目的是生成160拼接的字符串。
  2. 这里使用了点小技巧。
  3. new Array(17)构造了一个17个元素的数组,但是数组里面没有元素,
  4. join(atr)方法的作用是连接数组元素并且以其参数分割。17个元素正好有16个间隔,
  5. 所以最终拼接起来的字符串为16个。

ObjectId转换为字符串
    
  1. 在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码:
  2. >new ObjectId().str
  3. 以上代码将返回Guid格式的字符串::
  4. 5349b4ddd2781d08c09890f3

根据 ObjectId按照插入时间排序
     
  1. MongoDB默认在ObjectId上建立索引,是按照插入时间排序的。
  2. 我们可以使用此索引进行查询和排序。
  3. // 按序插入三个文档
  4. > db.col.insert({"num":1})
  5. > db.col.insert({"num":2})
  6. > db.col.insert({"num":3})
  7. > db.col.find().pretty()
  8. { "_id" : ObjectId("53102fb4bf1044ed8b0ba36c"), "num" : 1 }
  9. { "_id" : ObjectId("53102fb9bf1044ed8b0ba36d"), "num" : 2 }
  10. { "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }
  11. // 按照_id升序,即按照插入时间升序
  12. > db.col.find().sort({"_id":1}).pretty()
  13. { "_id" : ObjectId("53102fb4bf1044ed8b0ba36c"), "num" : 1 }
  14. { "_id" : ObjectId("53102fb9bf1044ed8b0ba36d"), "num" : 2 }
  15. { "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }
  16. // 按照_id降序,即按照插入时间降序
  17. > db.col.find().sort({"_id":-1}).pretty()
  18. { "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }
  19. { "_id" : ObjectId("53102fb9bf1044ed8b0ba36d"), "num" : 2 }
  20. { "_id" : ObjectId("53102fb4bf1044ed8b0ba36c"), "num" : 1 }
  21. // 抽取num = 2的ObjectId用来过滤
  22. > num2 = ObjectId("53102fb9bf1044ed8b0ba36d")
  23. ObjectId("53102fb9bf1044ed8b0ba36d")
  24. // 找出插入时间在num2之后的数据
  25. > db.col.find({ "_id":{$gt:num2}}).pretty()
  26. { "_id" : ObjectId("53102fbabf1044ed8b0ba36e"), "num" : 3 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萤火AI百宝箱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值