1、json和bson

JSON

JSON是一种简略的数据表示形式,它易于了解、易于解析、易于记忆。但从另一方面来说,因为只有null、布尔、数字、字符串、数组和对象这几种数据类型,所以JSON有肯定局限性。例如,JSON没有日期类型,JSON只有一种数字类型,无奈辨别浮点数和整数,更别说辨别32为和64位数字了。再者,JSON无奈示意其余一些通用类型,如正则表达式或函数。

BSON

BSON(Binary Serialized Document Format)是一品种JSON的二进制模式的存储格局,简称Binary JSON。它和JSON一样,反对内嵌的文档对象和数组对象,然而BSON有JSON没有的一些数据类型,如Date和BinData类型。它反对上面数据类型。每个数据类型对应一个数字,在MongoDB中能够应用$type操作符查看相应的文档的BSON类型

MongoDB毋庸申明数据类型,全自动匹配

每种BSON类型都具备整数和字符串标识符,如下表所示:

TypeNumberAliasNotes
Double1“double”
String2“string”
Object3“object”
Array4“array”
Binary data5“binData”
Undefined6“undefined”Deprecated.
ObjectId7“objectId”
Boolean8“bool”
Date9“date”
Null10“null”
Regular Expression11“regex”
DBPointer12“dbPointer”Deprecated.
JavaScript13“javascript”
Symbol14“symbol”Deprecated.
JavaScript (with scope)15“javascriptWithScope”Deprecated in MongoDB 4.4.
32-bit integer16“int”
Timestamp17“timestamp”
64-bit integer18“long”
Decimal12819“decimal”New in version 3.4.
Min key-1“minKey”
Max key127“maxKey”

2、数据类型

2.1、double类型

mongo shell 客户端默认将数字看成浮点数。

2.2、 64-bit integer(long)

BSON有两种整型数据类型:32位有符号整型数据(INT); 64位有符号型整型数据(LONG)

转换函数为 NumberLong(),

2.3、 32-bit integer (int)

32-bit integer (int)和64-bit integer(long)差不多,不同的是,其转换函数由NumberLong()变成了 NumberInt() ,其承受的参数,也当成string类型来解决。

2.4、decimal

Decimal 这个数据类型是在Mongo 3.4 才开始引入的。新增Decimal数值类型次要是为了记录、解决货币数据 ,例如 财经数据、税率数据等。有时候,一些科学计算也采纳Decimal类型。

因为mongo shell默认将数字当成double类型,所以也是须要显式的转换函数NumberDecimal(),其承受参数是string值。

mongos> db.testnum01.insert({_id:231,calc:NumberDecimal("1000.55")})

阐明:

int/long/decimal,参数承受类型是string,如果是数字(默认是double类型)也能够,然而有精度失落的危险,会把数字变成15位(小数点不计算在内)

2.5 数字类型相加测试

以上4中都为数字类型,进行decimal与个类型数字的相加测试,如果如下:

Decimal 与decimal/int/long类型相加,小数位不变;

decimal与double类型相加,小数位会变成14位。

mongos> db.testnum01.find({_id:231}){ "_id" : 231, "calc" : NumberDecimal("1004.55") }mongos> db.testnum01.updateOne({_id:231},{$inc:{calc:2}}){ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }mongos> db.testnum01.find({_id:231}){ "_id" : 231, "calc" : NumberDecimal("1006.55000000000000") }

2.6 object ID

相似于惟一的主键,蕴含12个字节:总共有24位16进制数形成,也就是12个字节。

{ "_id" : ObjectId("5f2a22f7aa56fc2fc978b159"), "calc" : 123456789012345680 }5f2a22f7 aa56fc 2fc9 78b159
#"5f2a22f7" 代指的是unix工夫戳,这条数据的产生工夫#"aa56fc" 代指某台机器的机器码,存储这条数据时的机器编号#"2fc9" 代指过程ID,多过程存储数据的时候,十分有用的#"78b159" 代指随机数,这里要留神的是,随机数的数字可能会呈现反复,不是惟一的#以上四种标识符拼凑成世界上惟一的ObjectID#只有是反对MongoDB的语言,都会有一个或多个办法,对ObjectID进行转换#能够失去以上四种信息#留神:这个类型是不能够被JSON序列化的这是MongoDB生成的相似关系型DB表主键的惟一key,具体由24个bit组成:0-8字节是unix工夫戳,9-14字节的机器码,示意MongoDB实例所在机器的不同;15-18字节的过程id,示意雷同机器的不同MongoDB过程。19-24字节是随机数

因为ObjectId中保留了创立的工夫戳,所以你不须要为你的文档保留工夫戳字段,
能够通过"getTimestamp()"来获取文档的创立工夫戳, 返回工夫戳

--返回工夫戳mongos> ObjectId("5f2a22f7aa56fc2fc978b159").getTimestamp()ISODate("2020-08-05T03:09:43Z")--返回字符串mongos> ObjectId("5f2a22f7aa56fc2fc978b159").str5f2a22f7aa56fc2fc978b159

2.7 string

utf-8字符串,记住肯定是utf-8字符串

2.8 arrays

数组或者列表,多个值存储到一个键 (list)

"hobby" : [ "羽毛球","足球","篮球"]

2.9 Object字典

"course" : {"name" : "MongoDB","price" : 1000}

2.10 Null

空数据类型 , 一个非凡的概念,None Null

2.11 timetamp工夫戳

"date" : 1528183743111

2.12 data

存储以后日期或工夫格局

 "date" : ISODate("2019-01-05T15:28:33.705+08:00")

3、mongo中应用大整数精度失落问题

Mongo shell中应用大整数字面量,但默认整数字面量类型却是双精度浮点数,导致失落精度

  • 问题形容:

通过mongo shell插入或更新一个大整数(长度约大于等于16位数字)时,例如:

mongos> db.testnum01.insert([{_id:100,calc:12345678901111111111},{_id:101,calc:NumberLong("1234567890123456789")}])

实际上插入的是

> db.testnum01.find(){ "_id" : 100, "calc" : 12345678901111112000 }{ "_id" : 206, "calc" : 12345678902222221000 }{ "_id" : 207, "calc" : 12345678903333333000 }{ "_id" : 101, "calc" : NumberLong("1234567890123456789") }
  • 剖析:

因为mongo shell实际上是一个js引擎,而在javascript中,根本类型中并没有int或long,所有整数字面量实际上都以双精度浮点数示意(IEEE754格局)。64位的双精度浮点数中,理论是由1bit符号位,11bit的阶码位,52bit的尾数位形成。

11bit的余-1023阶码使得双精度浮点数提供大概-1.7E308~+1.7E308的范畴,52bit的尾数位大略能示意15~16位数字(局部16位长的整数曾经超出52bit能示意的范畴)。

所以当咱们在mongo shell中间接应用整数时,实际上它是以double示意的,而当这个整数字大概超过16位数字时,就可能产生有些整数无奈准确示意的状况,只能应用一个靠近能示意的整数来代替。如下面例子中,存入20位的数字,实际上能无效示意的数字只有16位,另外4位产生精度失落的状况。

  • 解决办法:

应用NumberLong()函数结构长整型的类型,记住传入的参数肯定要加双引号,否则应用整数的话又会被当做double而可能失落精度。

留神:long类型:64bit,8字节有符号型,最大可存2^63-1=9223372036854775807

超过64位可存储为字符串:> db.testnum01.insert({_id:222,calc:"12345678901234567890"})

mongos> db.testnum01.insert({_id:200,calc:NumberLong(1234567890123456789)})mongos> db.testnum01.insert({_id:201,calc:NumberLong("1234567890123456789")})mongos> db.testnum01.find(){ "_id" : 200, "calc" : NumberLong("1234567890123456768") }   //最初2位精度不对{ "_id" : 201, "calc" : NumberLong("1234567890123456789") }mongos> db.testnum01.insert({_id:202,calc:NumberLong("9223372036854775808")})    --无奈写入2020-08-05T13:39:48.422+0800 E QUERY    [js] Error: could not convert string to long long :@(shell):1:35mongos> db.testnum01.insert({_id:202,calc:NumberLong("9223372036854775807")})   --能够写入WriteResult({ "nInserted" : 1 })mongos>

留神,除了在mongo shell(javascript语言环境中),在其余不反对长整型而默认应用浮点数代替示意的编程语言中也会存在相似问题,操作时肯定要注意。

4、判断某字段类型/长度

// 字段类型为2(string),示意有此字段,或者用: $exists: true  ,长度大于100mongos> db.testnum01.find({calc: {$type:2,$regex: /^.{100,}$/ }});mongos> db.testnum01.find({calc: {$exists: true, $regex: /^.{10,}$/ }});// 查问字段类型为long、double的mongos> db.testnum01.find({calc:{$type:"double"}})    --db.testnum01.find({calc:{$type:1}})mongos> db.testnum01.find({calc:{$type:"long"}})    --db.testnum01.find({calc:{$type:18}})