MongoDB ObjectId 详解
1. 什么是 ObjectId?
ObjectId 是 MongoDB 文档的默认唯一标识符(_id)。它是一个 12 字节 的 BSON 类型值,MongoDB 自动为每个文档生成一个 ObjectId,但用户也可以手动指定。
2. ObjectId 的结构
MongoDB 的 ObjectId 由 12 字节 组成,结构如下:
| 字节数 | 内容 | 说明 |
|---|---|---|
| 4 字节 | 时间戳 | 记录 ObjectId 生成的秒级时间戳(Unix 时间) |
| 5 字节 | 随机值 | 机器唯一标识,防止不同机器生成相同 ObjectId |
| 3 字节 | 计数器 | 递增的计数器,确保同一秒内的多个 ObjectId 唯一 |
- 示例
ObjectId:
65f3a13f4c7d6b58d0c8a7e2
拆解:
65f3a13f(时间戳)4c7d6b58d0(随机值)c8a7e2(计数器)
3. 如何生成 ObjectId
(1) MongoDB 自动生成
如果不指定 _id,MongoDB 在插入文档时会自动生成 ObjectId:
db.users.insertOne({ name: "Alice" })
自动生成:
{
"_id": ObjectId("65f3a13f4c7d6b58d0c8a7e2"),
"name": "Alice"
}
(2) 手动创建 ObjectId
可以使用 ObjectId() 方法手动创建:
db.users.insertOne({ _id: ObjectId("65f3a13f4c7d6b58d0c8a7e2"), name: "Bob" })
或者在 JavaScript 中创建:
new ObjectId()
4. ObjectId 相关操作
(1) 提取 ObjectId 生成时间
由于 ObjectId 包含时间戳,可以通过 getTimestamp() 方法获取创建时间:
var id = ObjectId("65f3a13f4c7d6b58d0c8a7e2");
id.getTimestamp()
输出:
ISODate("2024-03-09T12:34:39Z")
(2) 查询特定时间范围的文档
根据 ObjectId 的时间戳,可以查找某个时间段内的文档:
db.users.find({ _id: { $gte: ObjectId.fromDate(new Date("2024-03-01")) } })
这个查询会返回 2024-03-01 之后插入的所有文档。
5. ObjectId 的特点
✅ 唯一性:全球唯一,保证不会有重复 ID。
✅ 可排序性:因为包含时间戳,ObjectId 按时间递增。
✅ 节省空间:相比 UUID(16 字节),ObjectId 只占 12 字节,更节省存储。
但也有一些 限制:
❌ 可预测性:如果暴露了 ObjectId,可以推测创建时间,可能带来安全风险。
❌ 不适合外部查询:不像 UUID,ObjectId 适用于 MongoDB,但不便于与外部系统兼容。
6. ObjectId vs UUID
| 对比项 | ObjectId | UUID |
|---|---|---|
| 字节数 | 12 字节 | 16 字节 |
| 唯一性 | 全球唯一 | 全球唯一 |
| 是否包含时间 | ✅ 包含 | ❌ 不包含 |
| 排序特性 | ✅ 按时间递增 | ❌ 无顺序 |
| 存储开销 | 较小 | 较大 |
| 跨数据库兼容性 | 仅 MongoDB | 跨系统兼容 |
7. 总结
ObjectId是 MongoDB 的默认主键,保证唯一性、顺序性。- 包含时间戳,可以查询文档的创建时间。
- 适用于大多数场景,但如果需要跨系统兼容,建议使用 UUID。
更多详细内容可以关注其他相关文章!