MongoDB(三)基础概念简介

此文翻译整理自MongoDB 4.0官方文档的引言部分,本人英语水平有限,可能有出入的地方,请查看官方英文文档

数据库和集合(Databases and Collections)

MongoDB 储存 BSON 文档(BSON document),也就是数据记录,存储在集合(collection)中,集合(collection)存在于数据库(database)中。

数据库(Database)

在MongoDB中,数据库(database)保存着由文档(document)组成的集合(collection)。

在mongo shell中选择某一个数据库来使用,就发出use <db>声明即可,如下所示:

use myDB

创建一个数据库

如果一个数据库不存在,当你第一次向其中存储数据的时候MongoDB就会创建那个数据库。如此之来,你可以在mongo shell中使用如下的操作来切换到一个不存在的数据库:

use myNewDB

db.myNewCollection1.insertOne( { x: 1 } )

如上所示insertOne()操作不仅仅创建了数据库 myNewDB,也创建了 集合 myNewCollection1,如果这个数据库或集合不存在的情况下。

集合(collection)

MongoDB在集合(collection)中储存文档(document)。集合 就类似于 关系型数据库 中的 数据表

创建一个集合

如果一个集合不存在,那么MongoDB会在第一次往这个集合存入数据的时候创建它。

db.myNewCollection2.insertOne( { x: 1 } )
db.myNewCollection3.createIndex( { y: 1 } )

insertOne()和createIndex()操作都会分别创建对应的集合,如果它们不存在的话。

显式创建

MongoDB提供了db.createCollection()方法来显式创建一个集合,可以附带多个配置项,例如设置最大尺寸或者文档验证规则。如果没有指定这些选项,那么就不需要来显式地创建集合,因为只要你向不存在的集合中存入数据就会自动创建它们。

文档验证(Document Validation)

MongoDB 3.2版本新加入的功能

默认情况下,一个集合不会要求它的文档拥有相同的结构(schema);也就是说在单个集合中的文档不需要字段和数据类型都是一模一样的。

自MongoDB 3.2版本起,不管怎样,你能够在更新和插入操作期间对一个集合执行文档校验规则。

修改文档结构

在一个集合中改变文档的结构,例如添加新的字段,移除已存在的字段,或者改变字段值为新的类型,更新文档为新的结构。

唯一标识符(Unique Identifiers)

MongoDB 3.6版本新加入的功能

 集合都被分配了一个不可变的UUID。在所有副本集中集合UUID保持不变,对于分片集群中的分片来说也保持不变。

获取一个集合的UUID,运行listCollections命令或者db.getCollectionInfos方法。

视图(Views)

自从3.4版本起,MongoDB添加了创建只读视图的支持,可以创建已存在的集合的视图或者其他视图的视图。

创建视图

  • 给目前的create命令(还有db.createCollection)加上viewOn和pipeline选项:
    db.runCommand( { create: <view>, viewOn: <source>, pipeline: <pipeline> } )

    或者对视图指定一个默认的collation(collation用来指定不同语言的字符串比较规则,这样有利于数据的排序):

    db.runCommand( { create: <view>, viewOn: <source>, pipeline: <pipeline>, collation: <collation> } )
  • 一个新的mongo shell助手方法db.createView():
    db.createView(<view>, <source>, <pipeline>, <collation> )

注意:必须在同一个数据库中创建视图作为源集合

行为(Behavior)

视图展示了如下的行为:

只读(Read Only)

视图是只读的;对视图做写操作会报错。

视图支持如下的读操作:

  • db.collection.find()
  • db.collection.findOne()
  • db.collection.aggregate()
  • db.collection.countDocuments()
  • db.collection.estimatedDocumentCount()
  • db.collection.count()
  • db.collection.distinct()

使用索引和排序操作

  • 视图会使用基础集合(underlying collection)的索引

  • 当索引是基于基础集合(underlying collection)的时候,你不能直接创建,删除或者重建视图的索引或者获取一个视图的索引列表

  • 对于一个视图不能指定一个$natural排序,举个例子,下面的操作是无效的:

    db.view.find().sort({$natural: 1})

映射操作符限制(Projection Restrictions)

对于视图的find()操作不支持以下映射操作符:

  • $
  • $elemMatch
  • $slice
  • $meta

不可变的名称(Immutable Name)

不允许重命名视图。

创建视图

  • 视图是在读操作的时候根据需求计算出来的,MongoDB在视图上执行读操作作为基础的聚合管道(underlying aggregation pipeline)。视图不支持类似这样的操作:
    db.collection.mapReduce(),聚合中的$text操作符只在第一阶段是有效的, $geoNear 管道阶段和不赞成的geoNear命令
  • 如果聚合管道(aggregation pipeline)被用来创建视图阻止了 _id字段,视图中的文档就不会有_id字段

分片视图(Sharded View)

如果视图的基础集合是分片的,那么它们就被认为是分片的。如此之来,你不能对于from字段在$lookup和$graphLookup操作指定一个分片视图。

视图和Collation

  • 你可以在创建的时候给一个视图指定默认的collation。如果没有指定collation,那么默认的collation就会是“简易”二进制比较校对符(binary comparison collator)。也就是说,视图不会继承集合默认的collation。
  • 视图上的字符串比较会使用视图默认的collation。试图改变或者覆盖掉视图默认collation的操作会失败报错。
  • 如果涉及了多个视图的聚合操作,例如有$lookup或者$graphLookup,视图就必须拥有相同的collation。

全局视图定义(Public View Definition)

列出所有集合的操作,例如db.getCollectionInfos()和db.getCollectionNames(),也会包含视图在它们的输出结果中。

重要信息:

视图的定义是全局的;也就是说对于视图的db.getCollectionInfos()和explain操作会包含定义了视图的管道。如此之来,要在视图定义中避免直接关系到敏感字段和值。

移除视图

想要移除视图,就在视图上使用db.collection.drop()方法。

修改视图

通过移除和重新创建视图或者使用collMod命令可以修改视图。

视图支持的操作

命令 方法
create

db.createCollection()
db.createView()

collMod  
 

db.getCollection()
db.getCollectionInfos()
db.getCollectionNames()

find
distinct
count

db.collection.aggregate()
db.collection.find()
db.collection.findOne()
db.collection.countDocuments()
db.collection.estimatedDocumentCount()
db.collection.count()
db.collection.distinct()

固定集合(Capped Collections)

概述

固定集合(capped collection)是固定了大小的集合,它支持基于插入次序(Insertion Order)的插入和获取文档的高流量操作。固定集合以近似于环形缓冲的方式运作:一旦一个集合被分配的空间已经填满了,那么新的文档插入的时候就会覆盖旧的文档。

行为

插入次序(Insertion Order)

固定集合会保证去保护插入次序。因此,在插入次序的情况下查询不需要一个索引来返回文档。没有索引在顶上的情况,固定集合就能够支持高流量操作。

自动删除旧文档

为了给新文档空出位置,固定集合会自动删除集合中的旧文档不需要脚本或者直接的删除操作。

考虑下面的潜在使用场景:

  • 储存大容量系统生成的日志信息。在固定集合中没有索引插入文档的速度近似于直接在文件系统中写入日志的速度。此外,当管理内建的先进先出属性保持了事件的次序,当管理储存功能的时候。
  • 在一个固定集合中缓存小量的数据。自从读取缓存的操作比写入缓存的操作要重的时候,你要么需要保证这个集合总是保留在工作集中(也就是内存中),要么接受一些写入操作的性能损失对于被要求的索引或者一组索引。

举个例子,oplog.rs集合(一个存储了数据库的排好序的逻辑写入日志)使用了固定集合在副本集中存储了操作日志。从MongoDB 4.0开始,和其他固定集合不一样,oplog这个固定集合能够扩展它过去配置的大小限制来避免删除掉主要的操作入口(majority commit point)。

_id索引

固定集合默认拥有一个_id字段和一个在_id字段上的索引。

约束和建议(Restrictions and Recommendations)

更新(updates)

如果你计划要更新固定集合中的文档,创建一个索引使得更新操作不需要做一个集合的扫描。

文档大小(Document Size)

在版本3.2中修改

如果一个更新或者一个替换操作改变了文档的大小,那么这个操作会失败。

文档删除(Document Deletion)

在固定集合中你无法删除一个文档。想要去删除一个集合中的所有文档,使用drop()方法删除集合并且重建固定集合。

分片(Sharding)

不允许对一个固定集合分片。

查询效率(Query Efficiency)

使用自然次序去高效率地检索最近时间点被插入的元素。这稍微有点类似于日志文件的尾巴。

聚集$out(Aggregation $out)

聚集管道操作符(aggregation pipeline operator)$out不能够将结果写入固定集合中。

步骤

创建一个固定集合

必须明确使用db.createCollection()方法来创建固定集合,这个方法是mongo shell的对于create命令的一个助手。当创建一个固定集合的时候你必须以字节来指定集合的最大大小,这样MongoDB就会去预先分配空间给这个集合。固定集合的大小中包含了一小部分空间为内部管理来使用。

db.createCollection( "log", { capped: true, size: 100000 } )

如果 size 字段的值小于等于 4096,那么集合的大小限制就会是4096字节。另外,MongoDB将会提升提供的size值使它是一个256的倍数的整数。

此外,也许你也会指定集合的最大文档数量,使用 max 字段,如下面这个例子:

db.createCollection("log", { capped : true, size : 5242880, max : 5000 } )

重要:

size 参数总是需要指定,甚至当你已经指定了文档的最大条数 max。如果一个集合的大小触及了最大大小限制的话MongoDB将会移除旧的文档,这个操作会提前于触及最大文档条数的限制。

查询一个固定集合

如果你在固定集合上不指定次序执行一个find()操作,MongoDB会保证查询结果的顺序和插入数据时的顺序一样。

要将文档检索为与插入顺序相反的的次序,发出find()方法后连sort()方法带着设置为-1的$natural参数,如下面的例子:

db.cappedCollection.find().sort( { $natural: -1 } )

检查一个集合是否是固定集合

使用isCapped()方法确定是否一个集合是固定集合,就像下面这样:

db.collection.isCapped()

将一个集合转变成固定集合

可以将一个不固定的集合转变成固定集合,使用convertToCapped 命令:

db.runCommand({"convertToCapped": "mycoll", size: 100000});

size 参数使用字节指定了固定集合的大小。

这样就在操作的持续期间控制了一个数据库排他锁(exclusive lock)。其他锁住同一个数据库的操作将会被阻塞直到操作完成。查看这个链接了解关于锁数据库的信息

经历一段时间后自动删除数据

作为一个固定集合的可选操作,考虑MongoDB的 TTL(time to live,存活时间) 索引。这个链接里有详细描述,这些索引允许你使普通集合中的数据过期并且移除,基于date-typed自动的值和对应的索引的 TTL 值。

重要:

TTL 索引和固定集合不兼容。

尾指针(Tailable Cursor)

对于固定集合你可以使用一个 tailable cursor。这个指针和 Unix 系统的 tail -f 命令类似,tailable cursor 跟踪固定集合的结尾处。当新的文档被插入到固定集合中的时候,你可以使用 tailable cursor 继续检索文档。

文档(Documents)

MongoDB 将数据记录作为 BSON 文档。BSON是 JSON 文档的二进制表示,但是它比 JSON 格式包含了更多的数据类型。关于 BSON 的说明,请看这里的文档

文档的结构

MongoDB文档由一对对字段和值组成,例如下面的结构这样:

{
   field1: value1,
   field2: value2,
   field3: value3,
   ...
   fieldN: valueN
}

一个字段的值可以是任意 BSON 数据类型,包含其它文档,数组,和文档数组。举个例子,下面的文档包含不同类型的值:

var mydoc = {
               _id: ObjectId("5099803df3f4948bd2f98391"),
               name: { first: "Alan", last: "Turing" },
               birth: new Date('Jun 23, 1912'),
               death: new Date('Jun 07, 1954'),
               contribs: [ "Turing machine", "Turing test", "Turingery" ],
               views : NumberLong(1250000)
            }

上面例子中的字段中包含了下面的数据类型:

  • _id 容纳了ObjectId类型
  • name 容纳了一个嵌套的文档包含了first和last字段
  • birth 和 death 容纳了Date类型的值
  • contribs 容纳了字符串数组
  • views 容纳了NumberLong类型的值

字段名称(Field Names)

字段名称是字符串。

文档的字段名称有下面这些约束:

  • 字段名称 _id 被保留作为主键;它的值在集合中必须是唯一的,可以是任何类型除了数组。
  • 字段名称包含 null 
  • 高等级字段名称不能以美元符号字符开头。

另外,MongoDB 自从版本3.6起,服务器允许储存包含点(也就是.)和美元符号(也就是$)的字段名称。

重要:

MongoDB查询语言不能总是表示查询字段名称中包含这些字符的查询(查看SERVER-30575)。

直到查询语言添加支持之前,不建议使用$ 和 . ,MongoDB官方驱动不支持这两个符号。

 

BSON 文档可能拥有超过一个字段使用相同的名字。大多数MongoDB 接口,然而,将MongoDB 表示为一种结构(例如一个哈希表),不支持重复的字段名称的结构。如果你需要处理拥有超过一个字段名称相同的文档,请去查看这里的驱动文档

一些MongoDB内部进程创建的文档可能拥有重复的字段,但是从来没有一个MongoDB进程会往已经存在的用户文档里添加重复字段。

字段值限制

对于索引集合来说,索引字段的值有最大索引键长度限制。

点语法(Dot Notation)

MongoDB使用点语法来从一个数组中获取元素或者从一个嵌套文档中获取字段。

数组

指定或者获取一个数组的一个元素凭借从零开始的索引位置,数组名的后面连着点号和从零开始的索引位置,用引号围起来:

"<array>.<index>"

举个例子,在一个文档中给出下面字段:

{
   ...
   contribs: [ "Turing machine", "Turing test", "Turingery" ],
   ...
}

想要指定contribs数组中第三个元素,使用点号语法"contribs.2"。

嵌套文档

使用点语法指定或者获取嵌套文档的字段,嵌套文档后面连着点号和字段名,用引号围起来:

"<embedded document>.<field>"

举个例子,在一个文档中给出下面字段:

{
   ...
   name: { first: "Alan", last: "Turing" },
   contact: { phone: { type: "cell", number: "111-222-3333" } },
   ...
}
  • 指定name字段中的last字段,使用点语法"name.last"。
  • 指定contact字段中的phone文档中的number字段,使用点语法"contact.phone.number"。

文档限制(Document Limitations)

文档有如下特征:

文档大小限制

BSON文档最大大小是16 MB。

最大文档大小帮助保证一个单独的文档不能使用过多的内存,或者在传输的时候不能使用过多的带宽。想要存储大于最大限制大小的文档,MongoDB提供了 GridFS 接口。

文档字段次序

MongoDB基于写入操作保存了文档字段的次序,除了以下场景:

  • _id字段总是文档中的第一个字段。
  • 重命名字段名的更新操作可能会导致文档中自动的重新排序。

在版本2.6中的改变:自从版本2.6起,MongoDB积极地尝试保存文档中的字段顺序。在版本2.6之前,MongoDB不会积极尝试保存字段顺序。

_id字段

在 MongoDB 中,每一个保存在集合中的文档需要一个唯一的 _id 字段作为主键。如果插入一个文档省略了_id字段,MongoDB驱动会自动生成一个ObjectID给_id字段。

这也适用于通过update插入文档的操作,只要加上 upsert:true配置。

_id字段拥有如下行为和约束:

  • 默认情况下,MongoDB会在创建集合的阶段为_id字段创建一个唯一的索引。
  • _id字段总是文档中的第一个字段,如果服务器接收了一个第一个字段不是_id的文档,服务器会将_id字段移动到开头。
  • _id字段可能包含任意BSON数据类型,除了数组。

警告:

为了确保正在运行的复制,不要在_id字段中储存 BSON 正则表达式类型值。

 

下面的都是普遍的可以作为_id的值:

  • 使用一个ObjectId
  • 使用一个天然唯一的标识符,如果有现成的话。这样能节省空间避免额外的索引。
  • 生成一个自动增长的数字。
  • 在你的应用代码中生成一个UUID。有一种更加有效率的存储UUID值在集合中和_id索引中的方式,将UUID存储为BSON的BinData类型。
    索引键如果是BinData类型存储就会更有效率如果:
    二进制子类型值在0-7或者128-135范围内,字节数组的长度为:0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 32
  • 使用你的驱动的BSON UUID能力来生成UUID。注意驱动实现可能实现了不同的UUID序列化和反序列化逻辑,这就有可能不能和其他驱动完全兼容。

注意:

大多数MongoDB驱动客户端将会包含_id字段,并且在插入操作发送给MongoDB的时候生成一个ObjectID值;然而,如果客户端发送了一个没有_id字段的文档,mongod就会自动添加_id字段并且生成ObjectId。

文档结构的其他用途

除了定义数据记录之外,MongoDB自始至终都在使用文档结构,包含但是不限制于此:查询过滤器(query filters),更新规格文档(update specifications documents)和索引规格文档(index specification documents)。

查询过滤器文档(Query Filter Documents)

查询过滤器文档指定了确定哪一条记录会被选中来做读取,更新,删除操作的条件。

你可以使用<field>:<value>表达式来指定相等的条件和查询操作符(query operator)表达式。

{
  <field1>: <value1>,
  <field2>: { <operator>: <value> },
  ...
}

更新规格文档(Update Specification Documents)

更新规格文档使用更新操作符去指定数据修改在指定的字段上当db.collection.update()操作运行的时候。

{
  <operator1>: { <field1>: <value1>, ... },
  <operator2>: { <field2>: <value2>, ... },
  ...
}

索引规格文档(Index Specification Documents)

索引规格文档定义了索引字段和索引类型:

{ <field1>: <type1>, <field2>: <type2>, ...  }

BSON 类型(BSON Types)

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” 不赞成
ObjectId 7 “objectId”  
Boolean 8 “bool”  
Date 9 “date”  
Null 10 “null”  
Regular Expression 11 “regex”  
DBPointer 12 “dbPointer” 不赞成
JavaScript 13 “javascript”  
Symbol 14 “symbol” 不赞成
JavaScript (with scope) 15 “javascriptWithScope”  
32-bit integer 16 “int”  
Timestamp 17 “timestamp”  
64-bit integer 18 “long”  
Decimal128 19 “decimal” 3.4版本中新增
Min key -1 “minKey”  
Max key 127 “maxKey”  

 

你可以将这些值和$type操作符配合使用去根据它们的BSON类型查询文档。$type聚合操作符(aggregation operator)返回使用上面列出的某一种BSON类型字符串表示的操作符表达式(operator expression)的类型。

要去确定一个字段的类型,看这里的文档Check Types in the mongo Shell

如果想把BSON转换成JSON,看这里的文档Extended JSON

后面的内容会描述一些特别的BSON类型的特殊的考虑方面。

ObjectId

ObjectId占空间小,近似唯一,可快速生成,有次序的。ObjectId值由12个字节组成,它开头的4个字节是一个映射ObjectId创建时间的时间戳。按特性分为:

  • 一个4字节的值代表了秒单位的时间戳
  • 一个5字节的随机值
  • 一个3字节的计数器,起始值是随机值

在MongoDB中,每一个存储在集合中的文档需要一个唯一的_id字段来作为一个主键。如果一个被插入的文档省略了_id字段,MongoDB驱动会为_id字段自动地生成一个ObjectId。

这也适用于文档的插入,通过更新操作带有upsert:true选项。

MongoDB客户端应该添加一个_id字段带有一个唯一的ObjectId。对_id字段使用ObjectId类型可以提供以下额外的好处:

  • 在mongo shell中,你可以获取ObjectId的创建时间。使用ObjectId.getTimestamp()方法。
  • 基于存储ObjectId值的_id字段来排序在大体上和基于创建数据的时间排序是等价的。

重要:

当ObjectId类型的值应该根据时间增长而增长的时候,它们不一定必须是单调变化的。这是因为它们:

  • 只包含了二分之一的时间分辨率,所以在同一秒内被创建的ObjectId的值不会有一个被确定的次序。
  • 而且它们被客户端生成,有可能它们的系统时间会不一样。

字符串(String)

BSON字符串是UTF-8编码的。通常,每一种编程语言的驱动将其语言的字符串格式转变成UTF-8编码的当序列化和反序列化BSON格式的时候。这样使得它能够轻松地在BSON中存储大多出国际字符。另外,MongoDB 的$regex查询在正则字符串中支持UTF-8编码。

时间戳(Timestamps)

BSON对于MongoDB内部而言拥有一个特殊的时间戳类型,这个类型和规则的Date类型之间没有联系。时间戳的值是一个64位值:

  • 最开头的32位是一个 time_t 值(自从1970.1.1起的时间戳)
  • 后面的32位是一个自增的序数在一个所给的秒值范围内表示了不同的操作。

在一个单独的mongod实例中,时间戳的值总是唯一的。

在一个复制中,oplog 有一个 ts 字段。这个字段中的值映射了操作的时间点,使用了一个BSON时间戳值。

注意:

BSON时间戳类型是为MongoDB内部使用的。在大多数场景下,在应用开发的过程中,你使用BSON date类型就可以了。

 

如果你插入了一个包含了一个空的BSON时间戳的文档在高等级字段(top-level field)中,MongoDB服务器将会把那个空时间戳替换成当前的时间戳。举个例子,如果你插入一个文档带有一个时间戳值,像下面这样:

var a = new Timestamp();

db.test.insertOne( { ts: a } );

然后,db.test.find()操作将会返回一个文档类似于下面这样:

{ "_id" : ObjectId("542c2b97bac0595474108b48"), "ts" : Timestamp(1412180887, 1) }

如果 ts 是一个嵌套文档中的字段,服务器将会使其变为空时间戳值。

在版本2.6中的变化:以前,服务器会只替换空的时间戳值在开头的两个字段,包括 _id,在一个被插入的文档中。现在MongoDB将会替换任何高等级(top-level)字段。

日期(Date)

BSON Date格式是一个64位整数代表了自从1970.1.1起经历的时间的毫秒数。这个格式会产生一个从过去到未来大概290百万的时间范围内的时间。

官方BSON说明书中的BSON Date类型参考了UTC 日期时间。

BSON Date格式是有正负的。负数的值代表了1970年以前的时间。

下面是例子:

//在mongo shell中用new Date()构造器构造一个Date对象

var mydate1 = new Date()

//在mongo shell中用ISODate()构造器构造一个Date对象

var mydate2 = ISODate()

//返回 Date 字符串值

mydate1.toString()

//返回Date对象的月份部分;月份索引是以零开头的,所以一月会返回0

mydate1.getMonth()

比较/排序(Comparison/Sort Order)

当比较不同的BSON类型的值的时候,MongoDB使用下列比较次序,从低到高:

  1. MinKey (internal type)
  2. Null
  3. Numbers (ints, longs, doubles, decimals)
  4. Symbol, String
  5. Object
  6. Array
  7. BinData
  8. ObjectId
  9. Boolean
  10. Date
  11. Timestamp
  12. Regular Expression
  13. MaxKey (internal type)

数值类型(Numeric Types)

MongoDB对于比较的目的会将一些类型看作是相等的。举个例子,数值类型在比较之前会被转换类型。

字符串(Strings)

二进制比较(Binary Comparison)

默认情况,MongoDB使用简单的二进制比较来比较字符串。

Collation

在版本3.4中的新特性。

Collation允许用户指定对于字符串比较的特定于语言的规则,就像对于字母大小写和重音符号的规则。

Collation 有下面这些语法:

{
   locale: <string>,
   caseLevel: <boolean>,
   caseFirst: <string>,
   strength: <int>,
   numericOrdering: <boolean>,
   alternate: <string>,
   maxVariable: <string>,
   backwards: <boolean>
}

当指定了collation后,locals字段是强制的;所有其他collation字段都是可选的。关于这些字段的解释,查看Collation文档

如果对于集合或者操作没有指定collation,MongoDB 使用简单的二进制比较来比较字符串。

数组(Arrays)

对于数组,一个小于形式的比较或者一个递增排序会比较数组中的最小元素,一个大于形式的比较或者一个递减排序会比较数组中最大的元素。如此之来,当比较的双方,一个字段的值是一个只有一个元素的数组(例如[1]),另一个字段是非数组字段(例如 2),那么比较的就是1和2。一个空数组的比较(例如[])会将空数组处理成比 null 要小或者一个丢失的字段。

对象(Objects)

MongoDB对于BSON对象的比较使用如下次序:

  1. 递归地按照它们出现于BSON之中的次序来比较键值对。
  2. 比较键字段名称(key field names)。
  3. 如果键字段名称是相等的,就比较字段的值。
  4. 如果字段值是相等的,就继续比较下一个键值对(重回步骤1)。一个没有更深一层的对象比一个有更深层键值对的对象要小。

日期和时间戳(Dates and Timestamps)

版本3.0.0中新变化:Date对象排序优先于时间戳对象。之前的版本Date对象和时间戳对象是一起比较的。

不存在的字段(Non-existent Fields)

 

比较会将不存在的字段当做一个空的BSON对象。如此之来,一个对于{  } 文档中的a字段和{ a: null }比较的情况会认为它们是相等的。

BinData

MongoDB会将BinData类型按照下面的次序排序:

  1. 首先,数据的长度和大小
  2. 然后,对于BSON的单字节子类型
  3. 最后,对于数据,执行一个 字节接着字节的比较

MongoDB 扩展 JSON 

JSON只能表示BSON支持类型的一个子集。为了保存类型信息,MongoDB为JSON格式添加了如下扩展:

  • 严格模式。BSON类型的严格模式表示法遵循的规则是JSON RFC。任何JSON解析器都能将这些严格模式的表示解析成键值对;然而,只有MongoDB内部JSON解析器能识别这些由格式运输的类型信息。
  • mongo Shell 模式。MongoDB内部JSON解析器和mongo shell可以解析这个模式。

为各种数据类型所使用的表示取决于被解析的JSON的上下文。

解析器和支持的格式(Parsers and Supported Format)

严格模式中的输入(Input in Strict Mode)

下列方法可以通过对类型信息的识别在严格模式中解析JSON表示。

其他JSON解析器,包括 mongo shell 和 db.eval(),能够将严格模式的JSON表示解析成键值对,但是不包含类型信息的识别。

mongo shell 模式中的输入(Input in mongo Shell Mode )

下列方法可以通过对类型信息的识别在mongo shell 模式中解析JSON表示。

严格模式中的输出(Output in Strict mode)

mongoexport 和 REST 还有 HTTP 接口在严格模式中输出数据。

mongo shell 模式中的输出(Output in mongo Shell Mode)

bsondump命令在 mongo shell 模式中输出数据。

BSON数据类型和关联表示(BSON Data Types and Associated Representations)

下面是严格模式和mongo shell 模式 的BSON数据类型和联合表示。

Binary

data_binary

严格模式 mongo shell 模式
{ "$binary": "<bindata>", "$type": "<t>" } BinData ( <t>, <bindata> )
  • <bindata>是一个二进制字符串的base64表示
  • <t>是一个单个字节的表示来指明数据类型。在严格模式中它是一个十六进制字符串,在shell 模式中是一个整数。详细请查看bson文档http://bsonspec.org/spec.html

Date

data_date

严格模式 mongo shell 模式
{ "$date": "<date>" } new Date ( <date> )

在严格模式中,<date>是一个ISO-8601日期格式它在模板后面跟有一个强制的时间区域字段YYYY-MM-DDTHH:mm:ss.mmm<+/-Offset>。

MongoDB JSON 解析器当前不支持载入时间戳起始日期(1970年1月1日)之前的ISO-8601字符串代表的日期数据。当格式化时间戳之前的日期和过去的时间也就是操作系统的time_t类型保存的时间,以下的格式会被使用:

{ "$date" : { "$numberLong" : "<dateAsMilliseconds>" } }

在shell模式中,<date>是一个64位有符号整数代表时间戳之后时间的毫秒数的JSON表示。

Timestamp

data_timestamp

严格模式 mongo shell模式
{ "$timestamp": { "t": <t>, "i": <i> } } Timestamp( <t>, <i> )
  • <t>是一个32位无符号整数代表时间戳之后时间的秒数的JSON表示。
  • <i>是一个32位无符号整数表示增长值。

Regular Expression

data_regex

严格模式 mongo shell模式
{ "$regex": "<sRegex>", "$options": "<sOptions>" } /<jRegex>/<jOptions>
  • <sRegex>是一个有效JSON字符的字符串
  • <jRegex>是一个可能包含有效JSON字符和未转义双引号的字符串,但是可能不包含未转义的正斜杠字符(/)
  • <sOptions>是一个包含由字母表的字母组成的正则表达式选项的字符串
  • <jOptions>是一个可能只包含字母g,i,m,s的字符串(于版本v1.9中添加)。因为JavaScript和mongo shell的表示只支持有限范围的选项,任何不一致的选项在被转换成这种表示时将会被丢弃。

OID

data_oid

严格模式 mongo shell模式
{ "$oid": "<id>" }

ObjectId( "<id>" )

<id>是一个24个字母的十六进制字符串。

DB Reference

data_ref

严格模式 mongo shell模式
{ "$ref": "<name>", "$id": "<id>" }

DBRef("<name>", "<id>")

  • <name>是一个有效的JSON字符串。
  • <id>是任意有效的扩展JSON类型。

Undefined Type

data_undefined

严格模式 mongo shell模式

{ "$undefined": true }

undefined

这是javascript/BSON中的undefined类型的表示。

不可以使用undefined在查询文档里。考虑下面例子中被插入people 集合的文档:

db.people.insert( { name : "Sally", age : undefined } )

下面的查询返回一个错误:

db.people.find( { age : undefined } )
db.people.find( { age : { $gte : undefined } } )

然而,你可以使用$type来查询undefined值,如下:

db.people.find( { age : { $type : 6 } } )

这个查询返回所有age字段的值为undefined的文档。

MinKey

data_minkey

严格模式 mongo shell模式
{ "$minKey": 1 } MinKey

MinKey BSON 数据类型的表示,在比较的时候比其他类型都要小。

MaxKey

data_maxkey

严格模式 mongo shell模式
{ "$maxKey": 1 } MaxKey

MaxKey BSON 数据类型的表示,在比较的时候比其他类型都要大。

NumberLong

版本2.6新加入的类型

data_numberlong

严格模式 mongo shell模式
{ "$numberLong": "<number>" }

NumberLong( "<number>" )

 

NumberLong是一个64位有符号整型。你必须包含引号否则它会被解释为一个浮点数,结果丢失一些精确性。

举个例子,下面的命令插入9223372036854775807作为一个NumberLong类型,包含引号和不包含引号:

db.json.insert( { longQuoted : NumberLong("9223372036854775807") } )
db.json.insert( { longUnQuoted : NumberLong(9223372036854775807) } )

当你检索文档的时候,longUnQuoted字段的值变化了,而longQuoted字段会保留它的精度:

db.json.find()
{ "_id" : ObjectId("54ee1f2d33335326d70987df"), "longQuoted" : NumberLong("9223372036854775807") }
{ "_id" : ObjectId("54ee1f7433335326d70987e0"), "longUnQuoted" : NumberLong("-9223372036854775808") }

NumberDecimal

版本3.4中新加入的类型

data_numberdecimal

严格模式 mongo shell模式
{ "$numberDecimal": "<number>" }

NumberDecimal( "<number>" )

NumberDecimal是一个高精度小数。你必须包含引号,否则输入的数字会被作为一个double精度数,结果会有数据损失。

举个例子,下面的命令插入123.40作为一个NumberDecimal类型,有引号和没引号:

db.json.insert( { decimalQuoted : NumberDecimal("123.40") } )
db.json.insert( { decimalUnQuoted : NumberDecimal(123.40) } )

当你检索文档的时候,decimalUnQuoted的值发生了变化,而decimalQuoted依然保留了指定的精度:

db.json.find()
{ "_id" : ObjectId("596f88b7b613bb04f80a1ea9"), "decimalQuoted" : NumberDecimal("123.40") }
{ "_id" : ObjectId("596f88c9b613bb04f80a1eaa"), "decimalUnQuoted" : NumberDecimal("123.400000000000") }

 

posted @ 2019-01-25 12:00  hahazexia  阅读(1660)  评论(0)    收藏  举报