首页 / MongoDB 入门教程 / BSON 数据类型与 _id/ObjectId

MongoDB 入门教程

BSON 数据类型与 _id/ObjectId

本教程共 50 篇 · 第 9 篇 · 更新于 2026-07-30 · 约 8 分钟阅读

MongoDBMongoDB 入门教程BSONObjectId数据类型_id

9. BSON 数据类型与 _id/ObjectId

本节目标:认识 MongoDB 支持的主要数据类型,并搞懂每条文档的 _id 主键默认是怎么来的(ObjectId)。

9.1 常用类型一览

下面是写文档时最常遇到的几种 BSON 类型:

类型别名说明写法示例
Doubledouble双精度浮点19.99
StringstringUTF-8 字符串"北京"
Objectobject内嵌文档{ a: 1 }
Arrayarray数组[1, 2, 3]
Boolbool布尔true
Nullnull空值null
ObjectIdobjectId12 字节主键ObjectId()
Datedate日期时间ISODate(...)
BinarybinData二进制(文件等)BinData(...)
Decimal128decimal高精度小数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()
Tip

ObjectId 带了时间戳,所以「按 _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编码内容") })
Note

Date 类型在底层是「自 Unix 纪元起的毫秒数」的 64 位整数,可表示范围约正负 2.9 亿年,日常完全够用。