BSON 二进制 JSON 格式

FreeGuideOnline 最新 2026-07-13

<total_document_length>...<null_byte_terminator>


- 前 4 字节(int32)表示整个文档的字节长度(包含该长度字段自身)。
- 之后是一系列连续的 BSON 元素。
- 以一个 `0x00` 字节作为文档结束标记。

每个 BSON 元素的结构为:

<type_byte><element_name>


- `type_byte`:1 字节的类型标识符,用于指定紧随其后的值是什么类型。
- `element_name`:以 `0x00` 结尾的 UTF-8 字符串(即 C-style 字符串),表示字段名。
- `value`:具体数据的二进制表示,其格式取决于类型。

对于嵌套文档和数组,它们作为特殊类型的值嵌入,内部同样遵循上述文档结构。

### BSON 支持的主要数据类型

BSON 定义了一套固定的类型代码,下表列出了常用的类型及其代码:

| 类型代码 | 类型名称        | 说明                                 |
|----------|-----------------|--------------------------------------|
| `\x01`   | 64 位浮点数     | 对应 JSON 的 `number`,双精度         |
| `\x02`   | UTF-8 字符串    | 长度前缀的 UTF-8 字符串               |
| `\x03`   | 嵌入文档        | 嵌套的 BSON 文档                     |
| `\x04`   | 数组            | 嵌套的 BSON 文档,索引为字符串数字   |
| `\x05`   | 二进制数据      | 包含子类型和长度的任意字节序列       |
| `\x06`   | 未定义(已废弃) | 通常视作 null                        |
| `\x07`   | ObjectId        | 12 字节的唯一标识符                   |
| `\x08`   | 布尔值          | `\x00` 为 false,`\x01` 为 true      |
| `\x09`   | UTC 日期时间    | 64 位整数,自 UTC 纪元以来的毫秒数    |
| `\x0A`   | Null 值         | 无值,仅类型码和键名                 |
| `\x10`   | 32 位整数       | 有符号 32 位整数                     |
| `\x12`   | 64 位整数       | 有符号 64 位整数                     |

此外还有其他类型如 DBPointer、JavaScript 代码、正则表达式等,但上述为最常用类型。

### BSON 与 JSON 的对比

| 特性         | JSON                          | BSON                            |
|--------------|-------------------------------|---------------------------------|
| 格式         | 人类可读的文本                 | 二进制格式,不易直接阅读         |
| 数据类型     | 字符串、数字、布尔、数组、对象、null | 额外支持日期、二进制、ObjectId、int32/64 等 |
| 解析速度     | 需将字符串解析为数据结构,较慢   | 直接根据长度和类型标签进行跳转式解析,极快 |
| 存储空间     | 紧凑,但字段名重复存储         | 字段名同样会重复存储,通常比 JSON 稍大(因为加入类型信息),但对于二进制数据更高效 |
| 适用场景     | 配置文件、API 响应、数据交换   | 数据库存储、内部 RPC、驱动与服务器的通信 |
| 可遍历性     | 必须线性扫描                   | 可跳过不需要读取的部分             |

**重要误区澄清**:BSON 并不总比 JSON 体积小。对于纯文本数据,BSON 因为显式的类型字节和长度前缀,体积可能更大。其优势在于解析性能和二进制数据的高效处理。

### BSON 编码示例

假设有一个 JSON 文档:

```json
{
  "name": "Alice",
  "age": 30,
  "active": true
}

简化的 BSON 编码结构(十六进制表示,忽略具体长度字段细节):

\x00 整个文档长度占位...
\x02 'name\x00' \x05\x00\x00\x00 'A' 'l' 'i' 'c' 'e' \x00    ← UTF-8 字符串,前导 4 字节长度
\x10 'age\x00' \x1E\x00\x00\x00                                ← 32 位整数,小端序
\x08 'active\x00' \x01                                         ← 布尔值 true
\x00                                                            ← 文档结束

数组的编码方式与文档相同,只是将索引(如 "0", "1", "2")作为字段名,并顺序排列。

为什么 MongoDB 选择 BSON?

  1. 快速遍历:当查询只需要返回文档中的部分字段时,MongoDB 存储引擎可以利用 BSON 的长度前缀直接跳过不相关的字段,显著减少 I/O 和解析开销。
  2. 丰富的数据类型:MongoDB 支持日期范围查询、地理位置索引、二进制大对象存储等,这些都需要底层格式支持特定的数据类型。
  3. 原位更新:如果文档中某个字段的值大小不变,MongoDB 可以直接在磁盘上覆盖该值而不需要重写整个文档,BSON 的固定长度类型(如 int32、int64、double)对此提供了基础支持。
  4. 高效编码/解码:驱动端可以快速将语言原生类型映射到 BSON,无需像 JSON 那样进行复杂的类型推断和字符串处理。

如何在编程中使用 BSON

通常你不会直接操作 BSON 二进制流,而是通过 MongoDB 驱动程序或 BSON 库进行处理。以 Node.js 为例:

const BSON = require('bson');

// 将 JS 对象序列化为 BSON 二进制
const doc = { name: 'Alice', age: 30 };
const bsonBytes = BSON.serialize(doc);

// 从 BSON 二进制反序列化回 JS 对象
const deserializedDoc = BSON.deserialize(bsonBytes);
console.log(deserializedDoc); // { name: 'Alice', age: 30 }