数据类型
在概念上,MongoDB的文档与JavaScript中的对象相近,因而可以认为它类似于JSON。但JSON中只有null、布尔、数字、字符串、数组和对象这几种类型在数据库中表达有所局限,所以MongoDB也扩展了几种其他类型:
数据类型 | 描述 | 示例 |
---|---|---|
null | null用于表示空值或则不存在的字段 | {"x":null} |
布尔类型 | 只有true和false两个值 | {"x":true} |
数值 | 默认使用64位浮点数,即使看起来是整数 | {"x":3.14,"y":3} |
整数 | 整数分为表示4字节带符号整数NumberInt类和8字节带符号整数NumberLong类 | {"x":NumberInt("3"),"y":NumberLong("3")} |
字符串 | UTF8类型字符串 | {"x":"foobar"} |
日期 | 日期被存储为自1970年1月1日起的毫秒数,不存储时区 | {"x":new Date()} |
正则表达式 | 查询时,使用正则表达式作为限定条件,语法与JavaScript相同 | {"x":/foobar/i} |
数组 | 数据列表或数据集可以表示为数组 | {"x":[1,2,3]} |
内嵌文档 | 文档可嵌套其他文档 | {"x":{"foo":"bar"}} |
对象id | 对象id是一个12字节的ID,是文档的唯一标识 | {"x":ObjectId()} |
二进制数据 | 二进制数据是一个任意字节的字符串,它不能直接在shell中使用,如果要将非UTF-8字符保存在数据库中,二进制数据时唯一的方式,例如图片文件 | |
代码 | 查询和文档中可以包含任意JavaScript代码 |
日期
在JavaScript中,Date类可以用作MongoDB的日期类型,创建日期对象时应当使用new Date(...)而非Date(...)。如果使用Date()进行调用放回的是日期的字符串表示而不是Date对象。
shell根据本地时区设置显示日期对象,然而数据库中存储的日期仅为毫秒数,并未存储对应时区,如果有时区要求需要另一个键值。
_id和ObjectId
MongoDB中存储的文档必须由一个_id键,这个键的值可以是任何类型的,默认是个ObjectId对象,在一个集合里面,每个文档都有唯一的_id,确保集合里面每个文档都能被唯一标识,当然不同集合中的文档_id可以是一样的。如果插入文档时没有_id键,系统会自动帮你创建一个,这通常在客户端由驱动程序完成。
ObjectId作为_id的默认类型,而不是比较常规的使用自动增加的主键的原因是在多个服务器上同步自动增加主键即费力又费时,因为设计MongoDB的初衷就是作为分布式数据库,所有能够在分片环境中生成唯一的标识符非常重要。
ObjectId使用12字节的存储空间,是一个由24个十六进制数字组成的字符串,即每个字节可以存储两个十六进制数字。其每个字节的生成方式如下:
其中前4个字节是从1970年1月1日开始的时间戳单位是秒,也就是Linux时间戳。这会带来一些有用的属性:
- 时间戳,与随后的5字节组合起来,提供了秒级别的唯一性
- 由于时间戳在前,这意味着ObjectId大致会按照插入的顺序排列,这对某些方面很有用,但是这个是没有保证的,仅仅是大致
- 这4个字节也隐含了文档创建的时间,绝大多数驱动程序都会提供一个方法,用于从ObjectId获取这些信息
接下来的3字节是所在主机的唯一标识符。通常是机器主机名的hash值,这样就可以确保不同主机生成不同的ObjectId,不产生冲突。
为了确保在同一台机器上并发的多个进程产生的ObjectId是唯一的,接下来的两字节来自产生ObjectId的进程的进程标识符(PID)。
最后三个字节是一个自动增加的计数器,确保相同进程同一秒产生的ObjectId也是不一样的。
网友评论