ObjectId 是什么
ObjectId 是 MongoDB 默认的 _id 类型,共 12 字节:前 4 字节是创建时刻的秒级时间戳,中间 5 字节是进程随机值,最后 3 字节是以随机数起始的递增计数器。字符串形式是 24 位十六进制。它由客户端本地生成,插入前不需要向服务端申请主键,省掉一次往返;末尾递增的特性让同一进程的插入近似顺序写,避免像随机 UUID 那样造成索引页频繁分裂。
基本信息
| 长度 | 12 字节,表示为 24 位十六进制字符串 |
|---|---|
| 组成 | 4 字节时间戳 + 5 字节随机值 + 3 字节递增计数器 |
| 反解时间 | id.getTimestamp() |
| 生成方式 | new ObjectId() 或 ObjectId("24 位十六进制") |
| 唯一性 | 客户端生成,碰撞概率极低但需唯一索引兜底 |
典型使用场景
- 作为默认主键:绝大多数集合直接使用,无需额外声明
- 粗粒度按时间排序:_id 升序约等于插入顺序,可用于日志类集合浏览
- 反查写入时间:只拿到 _id 时用 getTimestamp() 还原创建时刻
- 键集分页:用 _id 大于上一页最后一条作为翻页条件,比 skip 高效
- 接口入参转换:外部传入的 24 位字符串要转成 ObjectId 再查询
生成与反解
生成与反解
const id = new ObjectId() // 客户端生成,不依赖服务端
id.getTimestamp() // 反解创建时间,只有秒级精度
id.toString() // 24 位十六进制,跨系统传参用这个形式
ObjectId("652b1c9a8f1b2c3d4e5f6a7b").getTimestamp()
// 键集分页:以上一页最后一条的 _id 为游标
db.orders.find({ _id: { $gt: ObjectId("652b1c9a8f1b2c3d4e5f6a7b") } })
.sort({ _id: 1 }).limit(20)结构逐段读法
| 区段 | 字节 | 含义 |
|---|---|---|
| 时间戳 | 4 | 自 Unix 纪元起的秒数,不精确到毫秒 |
| 随机值 | 5 | 每个客户端进程启动时生成一次,避免不同机器撞号 |
| 递增计数器 | 3 | 随机起始值,同进程内每次生成加一 |
| 字符串形式 | 24 | 十六进制字符,按字节序可直接比较大小 |
也可以拿业务键(订单号、设备号)当 _id,好处是天然唯一可读,代价是必须自己保证它永不变化;一旦 _id 改了,所有引用它的外部系统都要跟着改。
同一秒内的 ObjectId 顺序由计数器决定,跨进程比较不出严格先后,别把它当成全局递增序列号使用。