mongodb:数据类型、索引管理、字段约束管理,主键自增
数据类型
参考:
https://my.oschina.net/hfq/blog/1814731 (数据格式和数据类型)
https://docs.mongodb.com/manual/reference/bson-types/ (官方文档)
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类型
基本数据类型
null:用于表示空值或者不存在的字段,{“x”:null}
布尔型:布尔类型有两个值true和false,{“x”:true}
数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}
日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}
正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相同,{“x”:/[abc]/}
数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}
内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}
对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }
二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非utf-字符保存到数据库中,二进制数据是唯一的方式。
代码:查询和文档中可以包括任何JavaScript代码,{“x”:function(){/*…*/}}
BSON 与 MongoDB 的关系
BSON是用于存储MongoDB【文档】的一种文档格式。驱动程序在使用【文档】进行插入、查询或其他操作时。会先将【文档】编码成BSON格式,然后发送给服务器。同样地,服务器将文档返回客户端时,也是已BSON格式进行的。驱动程序先对此BSON进行解码然后再传送给客户端。因此,BSON与MongoDB的关系为:MongoDB利用BSON格式存储数据和传输数据
实例
db.getCollection('STOCK_INFO').insert({
marketno:'2',
stockno:'600055',
stock_name:'万东医疗',
issue_price:8.5400,//默认就是64为浮点型数值,存储到数据库后为8.54 ,后面2个0去掉了
quantity:NumberInt(15000000),//使用整型值。如果不加NumberInt函数,则存在数据库里面会带小数位
list_market:'上海证券交易所',
circ_trade_kind:'03',
industry_no:'c73',
created_by:'system',
updated_by:'system',
list_date:Date('1997-05-19'),//String类型 ,值为:Fri May 18 2018 11:39:34 GMT+0800
issue_date:new Date('1997-04-18'),//Date类型,值为:1997-04-18 00:00:00.000Z ,指定了日期,跟存入数据库一致。没有影响
created_date:ISODate('2016-06-17 13:55:18.000Z'), //Date类型,值为:2016-06-17 13:55:18.000Z ,跟准备的值一致,跟new Date比,最好用这个
delete_date:new Date('1997-04-18 10:33:12.000z'),//Date类型,值为:1970-01-01 00:00:00.000Z ,这个变为1970了,肯定错误了,不能用
select_date:ISODate('1997-04-18'),//Date类型 ,值为:1997-04-18 00:00:00.000Z.跟new Date比,最好用这个
updated_date:new Date(),//Date类型,值为当前系统时间,例如:2018-05-18 03:39:34.868Z ,是新纪元依赖经过的毫秒数,不存储时区.比电脑上显示的北京实际时间少8个小时
test_date:ISODate(),//Date类型,跟new Date()效果一样,但最好用ISODate。值为当前系统时间,例如:2018-05-18 03:39:34.868Z ,是新纪元依赖经过的毫秒数,不存储时区.比电脑上显示的北京实际时间少8个小时
assortment_id:'1'
});
索引
参考:
https://mongoing.com/archives/2797 (索引原理)
https://www.cnblogs.com/wyy1234/p/11032163.html (索引详解)
https://www.mongodb.com/docs/manual/indexes/(官方)
基本原理
MongoDB主要使用B+树作为其索引结构。B+树是一种自平衡的树,能够保持数据有序,并且允许对数据进行高效的插入、删除和查找操作。索引条目由键值对和指向相应文档的指针组成。
1,索引使用场景
经常用于比较的类(大于小于等于等),因为索引已经排序,值就是大于/小于的分界点;
经常进行范围搜索,因为索引已经排序,其指定的范围是连续的;
经常进行排序的列,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
经常进行分组的列,因为索引已经排序,同一个值的所有数据地址会聚集在一块,很方便分组。
2 mongoDB中常用的索引类型
1 单键索引
db.userinfos.createIndex({age:1})
2 复合索引
db.userinfos.createIndex({"name":1,"age":-1}) #name升序,age倒序
3 多键索引:针对数组字段
//情况1 :数组元素为对象 db.classes.insertMany([ { "classname":"class1", "students":[{name:'jack',age:20}, {name:'tom',age:22}, {name:'lilei',age:25}] }, { "classname":"class2", "students":[{name:'lucy',age:20}, {name:'jim',age:23}, {name:'jarry',age:26}] }] ) db.classes.createIndex({'students.age':1}) //情况2:数组元素不是复合数据 {"name" : "jack", "age" : 19, habbit: ["football, runnning"]} db.person.createIndex( {habbit: 1} ) // 自动创建多key索引
4 哈希索引
db.userinfos.createIndex({"name":"hash"})
5文本索引
db.collection.createIndex({ content: "text" })
3 mongoDB中常用的索引属性
1 唯一索引
db.userinfos.createIndex({name:1},{unique:true})
2 局部索引
//userinfos集合中age>25的部分添加age字段索引 db.userinfos.createIndex( {age:1}, { partialFilterExpression: {age:{$gt: 25 }}} ) //查询age<25的document时,因为age<25的部分没有索引,会全表扫描查找(stage:COLLSCAN) db.userinfos.find({age:23}) //查询age>25的document时,因为age>25的部分创建了索引,会使用索引进行查找(stage:IXSCAN) db.userinfos.find({age:26})
2 稀疏索引
db.userinfos.createIndex({address:1},{sparse:true})
4 TTL索引
TTL索引只能设置在date类型字段(或者包含date类型的数组)上,过期时间为字段值+exprireAfterSeconds;
//添加测试数据 db.logs.insertMany([ {_id:1,createtime:new Date(),msg:"log1"}, {_id:2,createtime:new Date(),msg:"log2"}, {_id:3,createtime:new Date(),msg:"log3"}, {_id:4,createtime:new Date(),msg:"log4"} ]) //在createtime字段添加TTL索引,过期时间是120s db.logs.createIndex({createtime:1}, { expireAfterSeconds: 120 })
集合的字段结构约束:还挺更重要
参考:https://www.mongodb.com/docs/manual/core/schema-validation/(官方)
字段和类型约束
db.createCollection("students", { validator: { $jsonSchema: { bsonType: "object", title: "Student Object Validation", required: [ "address", "major", "name", "year" ], properties: { name: { bsonType: "string", description: "'name' must be a string and is required" }, year: { bsonType: "int", minimum: 2017, maximum: 3017, description: "'year' must be an integer in [ 2017, 3017 ] and is required" }, gpa: { bsonType: [ "double" ], description: "'gpa' must be a double if the field exists" } } } } } )
查看集合元信息
db.getCollectionInfos( { name: "students" } )[0].options.validator
插入细节
这里有一个细节: 插入数据类型验证的时候,数字默认的格式是float/double 如果设置为int类型,就算本省是int格式的也需要NumberInt()转换一下,
字段名可以不加双引号""
:eg db.students.insertMany([{ "address":"北京", "major":"打工", "name":"kz", "year":NumberInt(3006), },{ address:"北京", major:"打工", name:"kz", year:NumberInt(3007), gpa:1212 }]);
主键自增
使用计数器集合
考虑下面的产品文档。我们希望_id字段从1,2,3,4到n,启动一个自动递增的整数序列。
{
"_id":1,
"product_name": "Apple iPhone",
"category": "mobiles"
}
对于这一点,创建一个计数器集合,将跟踪的最后一个序列值的所有序列字段。
db.createCollection("counters")
现在,我们将插入productid作为键,计数器集合如以下文档:
{
"_id":"productid",
"sequence_value": 0
}
字段 sequence_value 跟踪序列的最后一个值。
使用下面的代码插入到这个序列文档的计数器集合:
db.counters.insert({_id:"productid",sequence_value:0})
创建JavaScript函数
现在,我们将创建一个函数 getNextSequenceValue 将序列名称作为它的输入,递增序列号1,并返回更新后的序列号。在我们的例子中,序列的名字是 productid.
function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
new:true
});
return sequenceDocument.sequence_value;
}
使用JavaScript函数
现在,我们将使用 getNextSequenceValue 函数创建一个新文档并指派返回序列值作为文档的_id字段。
使用下面的代码来插入两个示例文档:
db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Apple iPhone",
"category":"mobiles"})
db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Samsung S3",
"category":"mobiles"})
正如所看到的,我们已经使用 getNextSequenceValue 函数来设置_id字段的值。
要验证的功能,让我们使用find命令来获取文件:
db.prodcuts.find()
上述查询返回下列文档具有自动递增_id字段:
{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}
{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }