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" }

 

posted @ 2021-01-07 23:39  小匡程序员  阅读(79)  评论(0编辑  收藏  举报