BSON 是一种二进制序列化格式,用在 MongoDB 中存储文档和进行远程过程调用。BSON 规范位于 bsonspec.org。
每个 BSON 类型都同时具有整数和字符串标识符,如下表所列:
类型 | 数值 | 别名 | 注意 |
|---|---|---|---|
double | 1 | "double" | |
字符串 | 2 | "string" | |
对象 | 3 | "object" | |
阵列 | 4 | "array" | |
二进制数据 | 5 | "binData" | |
未定义 | 6 | "undefined" | 已弃用。 |
ObjectId | 7 | "objectId" | |
布尔 | 8 | "bool" | |
Date | 9 | "date" | |
null | 10 | "null" | |
正则表达式 | 11 | "regex" | |
数据库指针 | 12 | "dbPointer" | 已弃用。 |
JavaScript | 13 | "javascript" | |
符号 | 14 | "symbol" | 已弃用。 |
带作用域的 JavaScript | 15 | "javascriptWithScope" | 已弃用。 |
32 位整数 | 16 | "int" | |
时间戳 | 17 | "timestamp" | |
64 位整型 | 18 | "long" | |
Decimal128 | 19 | "decimal" | |
Min key | -1 | "minKey" | |
Max key | 127 | "maxKey" |
要确定某一字段的类型,请参阅类型检查。
如果将 BSON 转换为 JSON,请参阅扩展 JSON 参考资料。
以下部分介绍了特定 BSON 类型的特别注意事项。
二进制数据
BSON 二进制binData值是字节数组。 binData值有一个子类型,用于指示如何解释二进制数据。 下表显示了子类型:
数值 | 说明 |
|---|---|
0 | 通用二进制子类型 |
1 | 函数数据 |
2 | 二进制(旧版) |
3 | UUID(旧) |
4 | UUID |
5 | MD5 |
6 | 加密的 BSON 值 |
7 | 压缩时间序列数据 5.2版本新增。 |
8 | 敏感数据,例如密钥或密码。 MongoDB 不会记录子类型为 8 的二进制数据的字面值。相反,MongoDB 会记录占位符值 |
9 | 向量数据是由相同类型的数字组成的密集数组。 |
128 | 自定义数据 |
ObjectId
ObjectId(对象标识符)很小,可能是唯一的,生成速度快并且是有序的。ObjectId 值的长度为 12 个字节,包含:
一个 4 字节时间戳,它表示 ObjectId 的创建时间,并以自 UNIX 纪元以来的秒数为单位进行测量。
5 字节的随机值,每个客户端进程生成一次。这个随机值对于机器和进程是唯一的。如果进程重新启动或进程的主节点发生变化,此值会被重新生成。
每个客户端进程的 3字节递增计数器,初始化为随机值。当进程重新启动时,计数器会重置。
对于时间戳和计数器值,最高有效字节在字节序列中最先出现(大端字节序)。对于其他 BSON 值,最低有效字节最先出现(小端字节序)。
如果使用整数值创建对象标识符(ObjectId),则该整数将替换时间戳。
In MongoDB, each document stored in a standard collection requires a unique _id field that acts as a primary key. If an inserted document omits the _id field, the MongoDB driver automatically generates an ObjectId for the _id field.
这也适用于通过执行 upsert: true 的更新操作插入的文档。
MongoDB 客户端应添加一个具有唯一 ObjectId 的 _id 字段。为 _id 字段使用 ObjectId 还能带来以下好处:
You can access
ObjectIdcreation time inmongoshusing theObjectId.getTimestamp()method.ObjectID 大致按创建时间排序,但并非完全有序。在包含
ObjectId值的_id字段上对集合排序,大致相当于按创建时间排序。
使用 ObjectId() 方法可设置和检索 ObjectId 值。
Starting in MongoDB 5.0, mongosh replaces the legacy mongo shell. The ObjectId() methods work differently in mongosh than in the legacy mongo shell. For more information on the legacy methods, see Legacy mongo Shell.
字符串
BSON strings are UTF-8. In general, drivers for each programming language convert from the language's string format to UTF-8 when serializing and deserializing BSON. This makes it possible to store most international characters in BSON strings with ease. [1] In addition, MongoDB $regex queries support UTF-8 in the regex string.
| [1] | 对使用 UTF-8 字符集的字符串,使用 sort() 对字符串进行排序通常可以得到正确的结果。但是,由于 sort() 内部使用 C++ strcmp API,因此某些字符的排序处理可能不正确。 |
时间戳
BSON has a special timestamp type for internal MongoDB use and is not associated with the regular Date type. This internal timestamp type is a 64 bit value where:
最高的 32 位有效位则是
time_t值(自 UNIX 纪元以来的秒数)对于给定秒内的操作,最低有效的 32 位是递增的
ordinal。
虽然 BSON 格式是小端字节序,因此首先存储最低有效位,但在所有平台上,mongod 实例始终先比较 time_t 值,然后再比较 ordinal 值,不受字节序的影响。
在复制中,oplog 有一个 ts 字段。该字段的值反映利用 BSON 时间戳值确定的操作时间。
在单个 mongod 实例中,oplog 中的时间戳值总是唯一的。
注意
The BSON timestamp type is for internal MongoDB use. For most cases, in application development, use the BSON date type. See Date for more information.
Date
“BSON Date”(BSON 日期)是一个 64 位整数,它表示自 UNIX 纪元(1970 年 1 月 1 日)以来的毫秒数。因此,过去与未来的可表示日期范围便可达到约 2.9 亿年。
官方BSON规范 将BSON Date 类型称为 UTC datetime。
BSON Date type is signed. [2] Negative values represent dates before 1970.
To construct a Date in mongosh, you can use the new Date() or ISODate() constructor.
使用 New Date() 构造函数创建日期对象
要使用 new Date() 构造函数来构建 Date,请运行以下命令:
var mydate1 = new Date()
mydate1 变量输出的日期和时间以 ISODate 格式封装:
mydate1
ISODate("2020-05-11T20:14:14.796Z")
使用 ISODate() 构造函数创建日期对象
要使用 ISODate() 构造函数来构建 Date,请运行以下命令:
var mydate2 = ISODate()
mydate2 变量存储一个日期和时间,并将其包装为 ISODate:
mydate2
ISODate("2020-05-11T20:14:14.796Z")
将日期转换为字符串
要以 string 格式打印 Date,请使用 toString() 方法:
mydate1.toString()
Mon May 11 2020 13:14:14 GMT-0700 (Pacific Daylight Time)
返回日期的月份部分
您还可以返回Date值的月份部分。月份从零开始索引,因此一月是第 0 个月。
mydate1.getMonth()
4
| [2] | 在 2.0 版本之前,Date 值被错误解释为无符号整数,这会影响针对 Date 字段的排序、范围查询和索引。由于升级时不会重新创建索引,因此,如果您使用早期版本对 Date 值创建了索引,则请重新创建索引,并且 1970 之前的日期与您的应用程序相关。 |
decimal128 BSON 数据类型
decimal128 是一种 128 位十进制表示形式,用于存储非常大或非常精确的数字,尤其适用于需要精确小数舍入的场景。它于 2009 年 8 月作为 IEEE 754-2008 浮点数修订标准的一部分推出。当您需要在处理 BSON 数据类型时达到高精度,您应使用 decimal128。
decimal128 支持 34 十进制精度(有效数字),指数范围为 -6143 到 +6144。尾数在 decimal128 标准中不做归一化处理,允许多种可能的表示形式:10 x 10^-1 = 1 x 10^0 = .1 x 10^1 = .01 x 10^2等。能够存储数量级高达 10^6144 和低至 10^-6143 的最大值和最小值,从而实现极高的精度。
结合 Decimal128() 构造函数来使用 decimal128 类型
在 MongoDB 中,您可以使用 Decimal128() 构造函数以 decimal128 格式存储数据。如果您将十进制值作为字符串传入,MongoDB 会将该值存储在数据库中,格式如下:
Decimal128("9823.1297")
您也可以将十进制值作为 double 传入:
Decimal128.fromStringWithRounding("1234.99999999999")
您还应该考虑您的编程语言对 decimal128 的使用情况和支持。以下语言不原生支持此功能,需要插件或附加包才能实现该功能:
Python:decimal.Decimal 模块可用于浮点运算。
Java: Java BigDecimal 类支持
decimal128数字。Node.js:有多个包提供支持,例如npm上提供的 js-big-decimal 或节点 bigdecimal。
用例
当您以编程方式进行数学计算时,有时会得到意想不到的结果。以下 Node.js 示例会产生不正确的结果:
> 0.1 0.1 > 0.2 0.2 > 0.1 * 0.2 0.020000000000000004 > 0.1 + 0.1 0.010000000000000002
同样,以下 Java 示例会产生不正确的输出:
1 class Main { 2 public static void main(String[] args) { 3 System.out.println("0.1 * 0.2:"); 4 System.out.println(0.1 * 0.2); 5 } 6 }
1 0.1 * 0.2: 2 0.020000000000000004
在 Python、Ruby、Rust 和其他语言中,相同的计算会产生相同的结果。发生这种情况是因为二进制浮点数不能很好地表示基 10 值。
例如,上述示例中使用的 0.1 在二进制中的表示为 0.0001100110011001101。大多数情况下,这不会引起任何显著的问题。然而,在金融、银行等对精度要求高的应用场景中,请使用 decimal128 作为数据类型。
带有MongoDB驱动程序的BSON
要查看特定驱动程序如何处理BSON,请参阅您的驱动程序文档: