BSON是一种二进制序列化格式,用于在MongoDB中存储文档和进行远程过程调用。BSON规范位于bsonspec.org上。
每种BSON类型都有整数和字符串标识符,如下表所示:
类型 | 编号 | 别名 | 注释 |
Double | 1 | "double" | |
String | 2 | "string" | |
Object | 3 | "object" | |
Array | 4 | "array" | |
Binary data | 5 | "binData" | |
Undefined | 6 | "undefined" | Deprecated. |
ObjectId | 7 | "objectId" | |
Boolean | 8 | "bool" | |
Date | 9 | "date" | |
Null | 10 | "null" | |
Regular Expression | 11 | "regex" | |
DBPointer | 12 | "dbPointer" | Deprecated. |
JavaScript | 13 | "javascript" | |
Symbol | 14 | "symbol" | Deprecated. |
JavaScript code with scope | 15 | "javascriptWithScope" | Deprecated in MongoDB 4.4. |
32-bit integer | 16 | "int" | |
Timestamp | 17 | "timestamp" | |
64-bit integer | 18 | "long" | |
Decimal128 | 19 | "decimal" | |
Min key | -1 | "minKey" | |
Max key | 127 | "maxKey" |
- $type操作符支持使用这些值按其BSON类型查询字段。$type还支持数字别名,与整数、十进制、双精度和长整型BSON类型匹配。
- $type聚合操作符返回其参数的BSON类型。
- $isNumber聚合操作符在版本4.4中新增,如果其参数是BSON整数、十进制、双精度或长整型,则返回true。
要确定字段的类型,请参见mongo Shell中的“检查类型”。
如果要将BSON转换为JSON,请参阅“Extended JSON reference”。
以下各节介绍特定BSON类型的特殊注意事项。
ObjectId
ObjectId是小型、可能唯一、生成速度快且有序的。ObjectId值长度为12字节,由以下组成:
- 4字节时间戳值,表示ObjectId的创建时间,以自Unix纪元以来的秒数为单位。
- 每个进程一次性生成的5字节随机值。该随机值对于计算机和进程而言是唯一的。
- 3字节递增计数器,初始化为随机值。
虽然BSON格式本身是小端格式,但时间戳和计数器值是大端格式,在字节序列中最显著的字节先出现。
在MongoDB中,存储在集合中的每个文档都需要一个唯一的_id字段,作为主键。如果插入的文档省略了_id字段,则MongoDB驱动程序会自动为_id字段生成ObjectId。
这也适用于通过upsert:true进行插入的文档更新操作。
MongoDB客户端应添加带有唯一ObjectId的_id字段。使用ObjectId作为_id字段提供以下附加效益:
- 在mongo shell中,可以使用ObjectId.getTimestamp()方法访问ObjectId的创建时间。
- _ id字段存储ObjectId值时的排序与按创建时间排序大致相当。
虽然ObjectId值随时间增加,但它们不一定单调递增。这是因为它们:
仅包含1秒的时间分辨率,因此在同一秒内创建的ObjectId值没有保证的排序;
是由客户端生成的,这些客户端的系统时钟可能不同。
String
BSON字符串是UTF-8编码的。通常,每种编程语言的驱动程序在序列化和反序列化BSON时都将其从该语言的字符串格式转换为UTF-8。这使得大多数国际字符可以轻松地存储在BSON字符串中。 [1] 此外,MongoDB $regex查询支持在正则表达式字符串中使用UTF-8。
[1] 给定使用UTF-8字符集的字符串,在字符串上使用sort()会比较正确。然而,由于内部sort()使用C++ strcmp API,因此排序顺序可能会错误处理某些字符。
Timestamps
BSON具有用于MongoDB内部使用的特殊时间戳类型,并且与常规Date类型无关。此内部时间戳类型是64位值,其中:
- 最高32位是time_t值(自Unix纪元以来的秒数)。
- 最低32位是给定秒内操作的递增顺序。
虽然BSON格式是小端格式,因此先存储最低有效位,但mongod实例在所有平台上始终比较time_t值和序数值,而不管字节序如何。
在单个mongod实例中,时间戳值始终唯一。
在复制中,oplog具有一个ts字段。该字段中的值反映了操作时间,使用BSON时间戳值作为其时间戳。
BSON时间戳类型是供MongoDB内部使用的。在大多数情况下,应用程序开发中,您可能希望使用BSON日期类型。有关更多信息,请参见“Date”。
当插入包含空时间戳值的顶级字段的文档时,MongoDB将这些空时间戳值替换为当前时间戳值,除非_id字段本身包含一个空时间戳值,否则它将始终按原样插入而不被替换。
例:
插入一个空timestamp的文档
db.test.insertOne( { ts: new Timestamp() } );
运行 db.test.find() 命令将返回一个类似以下文档的文档:
{ "_id" : ObjectId("542c2b97bac0595474108b48"), "ts" : Timestamp(1412180887, 1) }
服务器已经将ts字段的空时间戳值替换为插入时的时间戳值。
Date
BSON日期是一个64位整数,表示自Unix纪元(1970年1月1日)以来的毫秒数。这导致可表示的日期范围大约为290万年,包括过去和未来。
官方的BSON规范将BSON日期类型称为UTC日期时间。
BSON日期类型是有符号的。负值表示1970年之前的日期。
例:
在Mongo shell中使用new Date()构造函数构造一个日期:
var mydate1 = new Date()
在Mongo shell中使用ISODate()构造函数构造一个日期:
var mydate2 = ISODate()
将日期值作为字符串返回:
mydate1.toString()
返回一个日期值的月份部分,其中月份是从0开始计数的,因此1月为0:
mydate1.getMonth()
[2]在2.0版本之前,日期值被错误地解释为无符号整数,这影响了对日期字段的排序、范围查询和索引。由于在升级时不会重新创建索引,请重新创建索引(如果您在早期版本中使用日期值创建了索引)并且您的应用程序涉及1970年之前的日期。