1 JSON 与 BSON

MongoDB 是文档数据库,什么是文档呢?如果你看了之前的文章相信你已经有些概念了,这里的文档不是指 Word、PDF 这样的文档,而是类似 JSON(JavaScript Object Notation) 的对象,由不同的键以及对应的值组成,它的名字是 BSON(Bin­ary JSON)。

BSON 可以理解为 JSON 的扩展,我们先来认识下后者。JSON 是一种轻量的数据交换格式,常用于进程间通信、API 返回结果等方面。看个例子

{
    "name": "xiaoming",
    "age": 18,
    "is_student": true,
    "favorites": ["basketball", "sing"],
    "extra": {
        "height": 180,
        "country": "china"
    }
}

这就是一个 JSON 串,有如下特征

  • 以文本形式存储
  • 支持的简单类数据型:有字符串、数字、布尔值
  • 支持的复合数据类型有:数组、对象
  • 支持的特殊数据类型有:null
  • JSON 的最外层是一个数组或者对象

对于复合类型我做一些说明:

数组,由 0 到多个元素组成,多个中间以逗号隔开,外层使用方括号([])进行包裹,比如 favorites 字段对应的值就是一个数组。数组里面的元素可以是简单类型或者复合类型的一种或多种,也就是说不要求数组里的类型都相同。

对象,由 0 到多个键值对组成,多个中间以逗号隔开,外层使用花括号({})进行包裹,比如 extra 字段对应的值就是一个对象。其中的键只能是字符串,值可以是简单类型或者复合类型。这个例子中 JSON 的最外层也是一个对象。

JSON 轻量、易读,这是它的优势,不过也有些缺陷

  • 支持的类型不是很精确,比如数字,我们无法判定是整型还是浮点型,如果根据有没有小数点来区分,即使判定是整型了,它是 32 位的还是 64 位的我们也无从得知
  • 支持的类型不是很全,比如常用的时间类型没有

这样一来就引入了 BSON,它做了如下扩充

  • 数字支持更准确的类型,对于整型有 int32、int64 等,对于小数有 double、decimal128
  • 引入了 Timestamp、UTC datetime 等其它类型

需要注意的是,BSON 是以二进制形式存储的,所以可读性不高。另外,它的最外层只能是对象。

PS:如果比较好奇 JSON 和 BSON 的规范,可以看下文末的参考链接 1 和 2

2 MongoDB 中常见的数据类型

官方文档 BSON Types 一节(见参考链接 3)中对支持的数据类型列了一个表,我按自己的理解给大家梳理下。

JSON 支持的数据类型,BSON 肯定也支持,所以先用 JSON 去理解其中一部分数据类型

JSON 中的数据类型

MongoDB 中的数据类型

简单类型

数字

-

布尔

Boolean

字符串

String

复合类型

数组

Array

对象

Object

特殊类型

null

Null

BSON 对数字进行了一些扩充,我们记住常见的几个就行

  • 32-bit integer(32 位整数)
  • 64-bit integer(64 位整数)
  • Double(浮点数)
  • Decimal128(小数)

Double 和 Decimal128 有什么差别呢?你可以简单理解为后一种更加准确,前者存储的是一个大概值,后者则是存储一个准确值。比如,同样是 9.99,Decimal128 存储的是准确的,Double 则是存的 9.9900000000000002131628...。一般情况我们使用 Double 没有什么问题,但是在某些对数字准确度有较大要求的场景下就要使用 Decimal128,比如电商、金融行业等。另外,它们所占的存储空间也是不同的,前者是 8 个字节,后者是 16 个字节。

BSON 还扩充了一些类型,我们也挑几个常用的认识下

  • ObjectID

该类型主要用于文档唯一 _id 的生成,长度为 12 个字节

- 前 4 个字节记录的是时间戳
- 中间 5 个字节是随机数
- 后 3 个字节是计数器

MongoDB 3.2 以及之前的版本对于中间 5 个字节的生成策略有些不同:前 3 个是机器 ID,后 2 个是进程 ID。3.2 之后的版本使用的是随机数。

注意:本文在对字节进行前后描述时,前指的是高字节位,后指的低字节位

  • Timestamp

该类型主要用在 MongoDB 程序内部,用于标识操作的先后顺序,长度为 8 个字节

- 前 4 个字节记录的是时间戳
- 后 4 个字节记录的是在同一秒内某个操作的序号,这个序号是递增的,由于同一秒内经常会有多个操作,所以采用这种方式记录
  • Date

应用如果要用到时间类型的话,一般会使用这个数据类型,它的底层其实是一个 64 位的整数,记录的也是时间戳,不过单位是毫秒。

另外说明下,如果你看过 BSON 的规格描述,你会发现 MongoDB 中对于一些类型的命名和 BSON 有些差异。比如,MongoDB 官方文档中 Object 其实和 BSON 中的 document 是同一种数据类型,只是名字不同。我们不用过于纠结这些,只要记住一种命名,比如 MongoDB 官方文档中的,然后知道它代表着什么或者是怎么存的就行了。

如果需要比较全面的了解 MongoDB 中支持的数据类型,请查阅官方文档 BSON Types 一节(参考链接 3)。

3 使用 Compass 查看数据类型

我们打开 Compass,在集合 video.movies 的详情页面,打开 Schema 标签页,点击 ANALYZE 按钮后等待一小会后,我们可以看到文档中各字段值的数据类型



java数据类型int的位数怎么获取_double类型占几个字节

列下部分字段的数据类型

  • _id:ObjectId
  • cast:3 种数据类型,有 Array、String 和 Undefined。由于 MongoDB 不会对某个字段的类型做强制要求,也就出现了不同文档同一个字段类型不同的情况。Undefined 表示 cast 字段在某些文档中是不存在的
  • viewerRating:3 种数据类型,有 Double、32-bit integer 和 Undefined

PS:这个小节中,集合的类型信息我都没有列完,大家可以自己使用 Compass 看下,再看下其它集合的一些信息,然后对照前面的介绍熟悉一些常用的数据类型。

需要注意的是,上面的数据类型信息都是取样统计的(一般是取 1000 条,具体信息可以看查询框下的提示信息,比如上图样本量为 1000,总文档量为 963534,比例大概是 0.1%),并非统计的集合中的所有文档,所以不能百分百的保证全面。不过一般情况下这也够了,因为同一个集合中的文档字段大部分是相同的,即使有差异,取样的时候大概率也能取到,所以统计结果还是十分接近于真实情况的。

再看下集合 citibike.trips



java数据类型int的位数怎么获取_double类型占几个字节_02

也列下部分字段的数据类型

  • end station location:Object,其中子文档又有 2 个字段
  • coordinates:2 种数据类型,有 Array 和 Double
  • type:String
  • stop time:Date

字段 end station location 有点特殊,它的内容类似这样

"end station location": {
    "type": "Point",
    "coordinates": [-73.99973337, 40.71910537]
}

在 MongoDB 中可以以这种方式存储地理位置信息,type 指地理位置类型,coordinates 则指具体的坐标,这个对象在 MongoDB 中有个名字 GeoJSON object,可以理解为 MongoDB 基于 Object 类型扩展出的新的类型,但这个类型并非 BSON 规范所有。

在 Compass 中我们可以启用地理信息可视化的设置,依次点击菜单项 Help -> Privacy Settings,会有弹窗



java数据类型int的位数怎么获取_double类型占几个字节_03

勾选设置 Enable Geographic Visualizations 后,点击 Close 关闭弹窗,最后点击下 ANALYZE 重新生成统计信息



java数据类型int的位数怎么获取_double类型占几个字节_04

可以看到,Compass 对取样的文档中的地理位置进行了可视化。细心的伙伴可能会注意到,字段 end station location 下方展示的类型也从 document 变成了 coordinates,和前面 MongoDB 中的数据类型命名和 BSON 不一致一样,我们不用太纠结命名,知道 coordinates 指的是 GeoJSON object 就行了。

4 小结

本文简单介绍了 BSON,然后介绍了 MongoDB 中常用的 BSON 数据类型,最后借助 Compass 工具对这些类型进行了熟悉。

5 参考

  1. http://bsonspec.org/spec.html
  2. https://www.json.org/json-en.html
  3. https://docs.mongodb.com/manual/reference/bson-types