MongoDB 入门教程
BSON 数据类型与 _id/ObjectId
本教程共 50 篇 · 第 9 篇 · 更新于 2026-07-30 · 约 8 分钟阅读
MongoDBMongoDB 入门教程BSONObjectId数据类型_id
9. BSON 数据类型与 _id/ObjectId
本节目标:认识 MongoDB 支持的主要数据类型,并搞懂每条文档的
_id主键默认是怎么来的(ObjectId)。
9.1 常用类型一览
下面是写文档时最常遇到的几种 BSON 类型:
| 类型 | 别名 | 说明 | 写法示例 |
|---|---|---|---|
| Double | double | 双精度浮点 | 19.99 |
| String | string | UTF-8 字符串 | "北京" |
| Object | object | 内嵌文档 | { a: 1 } |
| Array | array | 数组 | [1, 2, 3] |
| Bool | bool | 布尔 | true |
| Null | null | 空值 | null |
| ObjectId | objectId | 12 字节主键 | ObjectId() |
| Date | date | 日期时间 | ISODate(...) |
| Binary | binData | 二进制(文件等) | BinData(...) |
| Decimal128 | decimal | 高精度小数 | NumberDecimal(...) |
Note据 MongoDB 8.3 官方文档,BSON 类型都有整数编号和字符串别名,例如 Date 编号 9、ObjectId 编号 7、Decimal128 编号 19。
9.2 数字类型要分清
MongoDB 里数字不止一种,混用会让人头疼:
Double:默认的小数,写19.99就是它。Int32 / Int64:整数,驱动一般按需选 32 位或 64 位。Decimal128:高精度小数,专治金额(详见下一章)。
// 显式指定类型
db.numbers.insertOne({
price: 19.99, // double
count: NumberInt(10), // 32 位整数
big: NumberLong(9000000000), // 64 位整数
money: NumberDecimal("19.99") // decimal128
})
9.3 ObjectId 长什么样
当你插入文档没写 _id,MongoDB 会自动补一个 ObjectId。它在 shell 里显示成:
ObjectId("665f1c2b9a1b2c3d4e5f6071")
ObjectId 一共 12 个字节,拆开看是这样:
- 前 4 字节:时间戳(秒级,自 Unix 纪元)。
- 中 5 字节:随机值(机器 + 进程相关)。
- 后 3 字节:自增计数器。
// 不写 _id,让 MongoDB 自动生成
db.users.insertOne({ name: "张伟" })
// 想看这个 id 是啥时候生成的
ObjectId("665f1c2b9a1b2c3d4e5f6071").getTimestamp()
TipObjectId 带了时间戳,所以「按 _id 排序」大致等同于「按创建时间排序」。但它不是严格单调的——同一秒生成的之间不保证顺序。
9.4 _id 是主键
_id 是每条文档的主键(Primary Key),在集合内必须唯一。
- 如果插入时没给
_id,驱动会自动生成一个 ObjectId。 - 如果你自己给了
_id,那它的值在集合里不能重复,否则报重复键错误(E11000)。 _id可以是除数组外的任意类型,但绝大多数场景用 ObjectId 或业务主键。
// 自己指定 _id(比如用业务里的用户编号)
db.users.insertOne({ _id: 1, name: "张伟" })
Warning
_id一旦写入不能改。想换主键只能删了重建。所以设计集合时就要想好_id用哪种。
9.5 日期与二进制的写法
日期用 ISODate,二进制用 BinData:
// 日期
db.events.insertOne({ at: ISODate("2024-01-15T08:30:00Z") })
// 二进制(subtype 0 是通用二进制)
db.files.insertOne({ data: BinData(0, "base64编码内容") })
NoteDate 类型在底层是「自 Unix 纪元起的毫秒数」的 64 位整数,可表示范围约正负 2.9 亿年,日常完全够用。