手记

mongodb基础概念实践

内容介绍

这里主要简单介绍一下mongodb基本使用和一些基本概念问题

nosql

大都知道mongodb是一个nosql的数据库,也有一些其他的nosql的典型数据库,比如redis,hbase等,然而他们之间还是有区分的

nametype
mongodb面向文档
redis键值存储
hbase列存储

虽然mongodb是非关系型数据库,然后他又是一个实现关系性最好的非关系数据库之一,然后又基于各种性能的优势,目前市面上备受推崇,或许postgresql也可以了解下,这里不做介绍,别问我为什么。

官网必须知道的几个点

  1. 数据类型

  2. MongoDB CRUD Operrations 基础增删改查

  3. Aggregation 聚合操作

  4. 查询调优

  5. 索引

123这三个点基本熟悉就代表能够满足平时的开发需求了,然后辅助一下数据结构设计的提升能更好的完成产品的开发;在123的基础上叠加45基本就能覆盖线上数据的搜索调优了。

吹牛没用,实践出真知

下面将会介绍部分简单的场景实例和操作想法

"实体结构"person:{    name:"string",
    age:"int",
    children:"array person",
    parentId:"string"}

首先创建表(collection)

//命令行
use testdb.createCollection("person")

表创建成功后在表中插入数据

//插入一个爸爸db.person.insertOne({
    name:"Baba",
    age:Int32(1234),
    children:[],
    parentId:null})//插入了几个儿子db.person.insertOne({
    name:"Child1",
    age:Int32(234),
    children:[],
    parentId:null})

db.person.insertMany(
[{
    name:"Child2",
    age:Int32(235),
    children:[],
    parentId:null},{
    name:"Child3",
    age:Int32(236),
    children:[],
    parentId:null}
])

嘿嘿,创建数据OK了,但是作为一个有梦想的程序员,必须要再了解一下script

//循环大法for(var i=0;i<10;i++){
    db.person.insertOne({    name:"robot"+i,    age:Int32(Math.floor(Math.random() * 100)),    children:[],    parentId:null})
}

截止到上一步我们已经在数据库test中的person表插入了几条数据了,这里做几个简单的查询熟悉下数据查询

//查询全部
db.person.find({})
//查询Baba
db.person.find({name:"Baba"},{age:1}).sort({age:1})
//查询不包含baba
db.person.find({name:{$ne:"Baba"}})
//查询年龄在(200,1000)的数据,$lte $gte中包含等于,时间的大于小于也是如此
db.person.find({age:{$lt:1000,$gt:200}},{age:1,_id:0})
//查询name中包含robot的数据,"i"代表忽略大小写,//就是正则
db.person.find({name:/robot/i}).skip(0*5).limit(5)
//或逻辑查询,$and为与逻辑,格式相同,而$and一般用于内嵌对象的与
db.person.find({$or:[{name:"Baba"},{name:/chi/i}]})

简单查询后,尝试一下update

//将名字叫Child1的parentId修改为Baba的_id//将baba的children的arr中填充Child1的_id并且年龄+1//注意push和addtoset的区别var baba =  db.person.findOne({name:"Baba"});
db.person.updateOne({name:"Child1"},{$set:{parentId:baba._id}})var child1 = db.person.findOne({name:"Child1"});
db.person.updateOne({_id:baba._id},{$addToSet:{children:child1._id},$inc:{age:1}})//重复多次运行会发现CHILDREN会出现重复数据db.person.updateOne({_id:baba._id},{$push:{CHILDREN:child1._id}})//查询children中不包含指定id的数据db.person.find({children:{$in:[child1._id]}})/////////////消失于江湖的华丽分割线//////////////////通过上面的语句会对set inc push addtoset有一定的了解,那就把CHILDREN中的移除吧,var baba =  db.person.findOne({name:"Baba"});var child1 = db.person.findOne({name:"Child1"});
db.person.updateOne({_id:baba._id},{$push:{"CHILDREN":new ObjectId()}})
db.person.updateOne({_id:baba._id},{$pull: {"CHILDREN":child1._id}})
db.person.updateOne({_id:baba._id},{$set:{"CHILDREN":[]}})//查看存在CHILDREN字段的数据db.person.find({CHILDREN:{$exists: true}})//彻底删除字段db.person.updateMany({},{$unset:{"CHILDREN":""}})

到这里大概已经涵盖了基础的增查改了,接下来让我们聚合一下

aggregate中的方法,这个链接里有所有的关键字使用介绍及demo,大家可以自行尝试。接下来介绍几个常用的关键字

db.person.updateMany({name:/robot/i},{$set:{obj:[
    {key:"db",value:"mongo"}, 
    {key:"db",value:"redis"}, 
    {key:"db",value:"hbase"}
    ]}})

db.person.aggregate()
      .match({name:/robot/i})  //query
      .project({nm:"$name",_id:1,age:1,obj:1})  //精简属性
      .unwind("$obj") //一般用来切分内嵌array,做数据聚合时经常会用到
      .group({ _id: "$nm", count: { $sum: 1 } }) //按照某个键分组聚合
      .sort({"count":-1})
      .limit(5)
//这句比较特殊,处理内嵌数组对象的值,$elemMatch是筛选内嵌array对象的关键字,该查询匹配到的数据将会在Mongo内存中把内嵌array匹配到的对象置顶与array的第一个,而接下来的"obj.$.value"是将改内嵌array对象中的第一个的value修改成"mongodb"db.person.updateMany({obj:{$elemMatch: {value:"mongo"}}},{$set:{"obj.$.value":"mongodb"}})

//类关系型数据库join
db.person.aggregate(
[{    $lookup: {
           from: "person",
           localField: "_id",
           foreignField: "parentId",
           as: "sons"
     }
}])

这里是3.6新加的Mongodb特性

mongodb version 4.0新增了transaction(事务)的功能,真的可以向mysql,mssql那样回滚了,不是像redis事务那样的,大家可以去了解下。

查询调优

这里简单的介绍最常用的一个

//这里match是让你填筛选条件,请别搞错db.collection.find({"match"}).explain("executionStats")//查询结果关键字含义executionStats.executionSuccess:是否执行成功
executionStats.nReturned:满足查询条件的文档个数,即查询的返回条数
executionStats.executionTimeMillis:整体执行时间
executionStats.totalKeysExamined:索引整体扫描的文档个数,和早起版本的nscanned 是一样的
executionStats.totalDocsExamined:document扫描个数, 和早期版本中的nscannedObjects 是一样的
executionStats.executionStages:整个winningPlan执行树的详细信息,一个executionStages包含一个或者多个inputStages
executionStats.executionStages.stage:这里是FETCH去扫描对于documents,后面会专门用来解释大部分查询使用到的各种stage的意思
executionStats.executionStages.nReturned:由于是FETCH,所以这里该值与executionStats.nReturned一致
executionStats.executionStages.docsExamined:与executionStats.totalDocsExamined一致executionStats.inputStage中的与上述理解方式相同
explain.executionStats.executionStages.works:被查询执行阶段所操作的“工作单元(work units)”数。
explain.executionStats.executionStages.advanced:优先返回给父stage的中间结果集中文档个数
explain.executionStats.executionStages.isEOF:查询执行是否已经到了数据流的末尾//stage类型的含义COLLSCAN :全表扫描
IXSCAN:索引扫描
FETCH::根据索引去检索指定documentSHARD_MERGE:各个分片返回数据进行merge
SORT:表明在内存中进行了排序(与前期版本的scanAndOrder:true一致)
SORT_MERGE:表明在内存中进行了排序后再合并
LIMIT:使用limit限制返回数
SKIP:使用skip进行跳过
IDHACK:针对_id进行查询
SHARDING_FILTER:通过mongos对分片数据进行查询
COUNT:利用db.coll.count()之类进行count运算
COUNTSCAN:count不使用用Index进行count时的stage返回
COUNT_SCAN:count使用了Index进行count时的stage返回
SUBPLA:未使用到索引的$or查询的stage返回
TEXT:使用全文索引进行查询时候的stage返回

索引

索引方面直接点上方的链接吧,官方这个讲的还是比较好理解的,这里不说了。

总结

撸起袖子动动手,光知道概念不尝试心里没底的。



作者:太白菜Rennbon
链接:https://www.jianshu.com/p/f8dbe24b91e8

0人推荐
随时随地看视频
慕课网APP