MongoDB-基本操作语法
1.MongoDB概念
1.1.业务场景
- 回顾:传统的关系型数据库(Mysql),在数据操作的’三高’需求以及应对Web2.0网站需求面前,显得力不从心。
- 解释:三高
- 对数据库高并发读写的需求 - High performance;
- 对海量数据的高效存储和访问的需求 - Huge Storage;
- 对数据库的高可扩展和高可用性的需求 - High Scalability && High Avallability;
- 解决:MongoDB应对三高
- 应用场景
- 社交场景:存储用户信息,用户发表朋友圈信息,通过地理位置索引实现附近的人,地点等功能。
- 游戏场景:用户信息,用户装备,积分等直接以内嵌文档的形式存储,高效存储和访问。
- 物流场景:存储订单信息,订单状态在运送过程中会不断更新,以MongoDB内嵌数组的形式存储,一次查询可以将订单所有的变更读取出来。
- 物联网场景:存储智能设备信息,设备的日志信息,并对这些信息多维度分析。
- 视频直播:存储用户信息,点赞互动信息等。
- 场景特点
- 数据量大
- 读写操作频繁
- 价值较低,事务性要求不高
- 应用场景
- 选择:何时选择MongoDB(满足2条以上即可选择)
- 不需要事务,复杂的join-----可使用MongoDB内嵌的形式
- QPS达到3000+
- 数据存储在TB-PB级别
- 大量文本查询操作
- 应用需要99.99%高可用
1.2.MongoDB简介
- MongoDB是一个非关系型数据库,开源,高性能,无模式的文档型数据库;
- MongoDB数据结构类似于JSON格式的BSON,可存比较复杂的数据类型;
- MongoDB记录的是一个文档,是由字段和值对(filed:value)组成的数据结构,filed为字符型,value为基本数据类型,文档,普通数组,文档数据等等。
1.3.MongoDB与Mysql
1.3.1数据结构区别
SQL | MongoDB | 说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
嵌入文档 | MongoDB通过嵌入式文档代替多表连接 | |
primary key | primary key | 主键,MongoDB自动将id字段设置为主键 |
2.常用命令
2.1选择和创建数据库
2.1.1.选择和创建数据库的语法格式
use 数据库名称 --如果数据库不存在则自动创建
2.2.2.查看有权限查看的所有的数据库命令
show dbs
show databases
2.2.3.查看当前正在使用的数据库命令
db --MongoDB中默认的数据库为test,如果没有选择数据库,集合将存放在test数据库中。
注意:数据库命名规则:满足以下条件的任意UTF-8字符串
- 不能是空字符串(“”)。
- 不能含有‘ ’(空格)、.、$、/、\和\0(空字符)
- 应全部小写
- 最多64字节
自带三个库:
- admin:从权限的角度来看,这是’root’数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者被关闭服务器。
- local:这个数据永远不会被复制,可以采用存储限于本地单台服务器的任意集合。
- config:当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
2.2删除数据库
2.2.1.删除数据库的语法格式:
db.dropDatabase() -- 主要用来删除已经持久化的数据库 db泛指当前使用数据库,删除的是当前使用db
2.3集合操作
2.3.1.集合显式创建(了解即可)
db.createCollection(name) -- 基本语法
例如:db.createCollection("mycollection") -- 创建名为mycollection的普通集合
- 参数说明:name-要创建的集合名称
- 查看当前库中的表:
show collection
show tables
- 集合命名规范:
- 集合名不能是空字符串""
- 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾
- 集合名不能以"system."开头,这是为系统集合保留的前缀
2.3.2.集合的隐式创建
- 当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合。
- 注意:通常使用隐式创建
2.3.3.删除集合
db.collection.drop() -- 删除集合语法格式
例如:db.douglascollection.drop() --删除名为douglascollection集合
注意:如果成功删除选定集合,则drop()方法返回true,否则返回false。
2.4文档CURD
- 文档(document)的数据结构和JSON基本一致,所有存储在集合中的数据都是BSON格式。
2.4.1.插入单个文档
- 单个文档插入
- 使用insert()或save()方法向集合中插入文档,语法如下:
db.collection.insert(
<document or array of documents>
{
writeConcern:<document>,
ordered:<boolean>
}
)
- 参数说明:
参数 | 类型 | 说明 |
---|---|---|
document | document/array | 要插入到集合中的文档或文档数组(json格式) |
writeConcern | document | 选择插入的性能级别,详情可见: |
ordered | boolean | 可选,如果为true,则按顺序插入数组中的文档,如果其中一个文档出现错误,MongoDB将返回而不处理数组中其余文档。如果为false,则执行无序插入,如果其中一个文档出现错误,则继续处理数组中的主文档。在2.6+版本中默认true |
- 【案例】:向douglas集合(表)中插入一条数据:
db.douglas.insert(
{
"number":"516300284106",
"name":"LD",
"content":"好好学习,天天向上",
"workNo":"1001",
"createtime":new Date(),
"likenum":NumberInt(10),
"state":null
}
)
-
【注意】:
- douglas集合如果不存在,则会隐式创建;
- mongoDB中的数字,默认是double类型,如果存整型,必须使用函数NumberInt(整型数字),否则取出会产生问题;
- 插入当前日期使用new Date()函数;
- 插入的数据没有指定_id,会自动生成主键值;
- 如果某字段没有值,可以赋值null,或不写该字段
-
【执行结果】
WriteResult({"nInserted":1})
2.4.2.插入批量文档
- 【语法】
db.collection.insertMany(
[<document 1>,<document 2>,...]
{
writeConcern:<document>,
ordered:<boolean>
}
)
- 【参数】
- 与单个插入参数一致
- 【案例】
db.douglas.insertMany([
{
_id:"1",
"number":"516300284107",
"name":"YMWM",
"content":"以梦为马,不负韶华",
"workNo":"1003",
"createtime":new Date(),
"likenum":NumberInt(99),
"state":"离线"
},
{
_id:"2",
"number":"516300284108",
"name":"WLKQ",
"content":"少年-未来可期",
"workNo":"1004",
"createtime":new Date(),
"likenum":NumberInt(88),
"state":"在线"
},
{
_id:"3",
"number":"516300284109",
"name":"LS",
"content":"请问你今天努力了么?",
"workNo":"1005",
"createtime":new Date(),
"likenum":NumberInt(66),
"state":"连接中"
}
]);
- 【注意】
- 插入时指定了_id,则逐渐就是该指定值。
- 如果某条数据插入失败,将会终止插入,但是已经插入成功的数据不会回滚。
- 因此批量插入由于数据较多容易出现失败,因此,可以使用try catch进行异常捕获处理,如下:
try{
db.douglas.insertMany([
{
_id:"1",
"number":"516300284107",
"name":"YMWM",
"content":"以梦为马,不负韶华",
"workNo":"1003",
"createtime":new Date(),
"likenum":NumberInt(99),
"state":"离线"
},
......
]);
}catch(e){
print(e)
}
2.4.3.查询文档
db.collection.find(<query>,[projection]) -- 查询数据的语法格式
- 【参数】:
参数 | 类型 | 说明 |
---|---|---|
query | document | 可选,查询指定的筛选器,若要返回集合中的所有文档,请省略此参数或传递空文档({})。 |
projection | document | 可选,指定要在与查询筛选器匹配的文档中返回的字段(投影)。若要返回匹配文档中的所有字段,请省略此参数。 |
- 【案例】:
- 1.查询所有:两种方式
db.douglas.find()
db.douglas.find({})
2.4.3.1.单个条件查询
- 【语法】两种方式:
db.douglas.find({"workNo":"1005"}) -- 查询workNo为1005的信息
2.4.3.2.投影查询
- 【语法】 Projection Query
db.douglas.find({workNo:"1005"},{number:1,name:1}) -- 查询结果只显示 _id,number,name
-
【作用】
- 查询返回部分字段,则选择投影查询(不显示所有字段,只显示指定的字段)
-
【注意】默认_id会显示
- 查询只显示结果,不需要_id
db.douglas.find({workNo:"1005"},{number:1,name:1,_id:0})
2.4.4.更新文档
2.4.4.1.更新文档语法
- 【语法】两种方式
db.collection.update(query,update,options)
db.collection.update(
<query>,
<update>,
{
upsert:<boolean>,
multi:<boolean>,
writeConcern:<document>,
collation:<document>,
arrayFilters:[<filterdocument>,...],
hint:<document|string>
}
)
- 【参数】:
参数 | 类型 | 说明 |
---|---|---|
query | document | 更新的选择条件,可以使用与find()方法中相同的查询选择器,类似sql的update查询内where后面的。 |
update | document ||pipeline | 要应用的修改,该值可以是:包含更新运算符表达式的文档,或仅包含:对的替换文档。 |
upsert | boolean | 可选,如果为true,则在没有与查询条件匹配的文档时创建新文档。默认为false,如果找不到匹配项,则不会插入新文档。 |
multi | boolean | 可选,如果为true,则更新符合查询条件的多个文档。如果为false,则更新一个文档,默认值为false。 |
writeConcern | document | 可选,表示写问题的文档,抛出异常的级别。 |
collection | document | 可选, |
arrayFilters | array | 可选,一个筛选文档数组,用于确定要为数组字段上的更新操作修改哪些数组元素。 |
hint | document||string | 可选,指定用于支持查询谓词的索引的文档或字符串。该选项可以采用索引规范文档或索引名称字符串。如果指定的索引不存在,则说明操作错误。 |
2.4.4.2.覆盖修改
- 【语法】修改id为1的数据,字段likenum=55,如下:
db.douglas.update({_id:"1"},{likenum:NumberInt(55)})
- 【结果】数据只剩下likenum字段了,其余字段不见了,因为覆盖修改,相当于给id=1重新写入数据。
2.4.4.3.局部修改
- 【语法】为了解决覆盖修改造成其余字段丢失,需要用局部修改命令如下:
db.douglas.update({_id:2},{$set:{likenum:NumberInt(999)}})
- 【结果】符合需求
2.4.4.4.批量修改
- 【语法】更新所有用户workNo为1003的name值为:douglas
-- 如下命令默认只会修改符合条件的第一条数据
db.douglas.update({workNo:"1003"},{$set:{name:"douglas"}})
-- 修改所有符合条件的数据
db.douglas.updateMany({workNo:"1003"},{$set:{name:"douglas"}}),{multi:true}
- 【结果】如果不加后面参数,则只更新符合条件的第一条记录
2.4.4.5.列值增长修改
- 【语法】:实现在某列值的原有值的基础上进行增加或减少,可以使用$inc运算符实现
- 【需求】:对id=3数据的likenum值每次递增1
db.douglas.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
2.4.5.删除文档
- 【语法】
db.集合名称.remove(条件)
- 【案例】删除整个数据库 慎用
db.douglas.remove({})
- 【案例】删除id=1的记录,如下:
db.douglas.remove({_id:"1"}) -- 目前新版本已经弃用
db.douglas.deleteOne({_id:"1"}) -- 新版本语法-删除单条数据
db.douglas.deleteMany({workNo:"1003"}),{multi:true} -- 批量删除
2.5分页查询数据
2.5.1.统计查询
- 【语法】统计查询使用count()方法
db.douglas.count(query,options)
- 【参数】
参数 | 类型 | 说明 |
---|---|---|
query | document | 查询选择条件 |
options | document | 可选.用于修改计数的额外选项. |
-
【案例】
- 统计所有记录:
db.douglas.count() -- 统计douglas集合的所有的记录数据
- 按条件统计记录数据:
db.douglas.count({workNo:"1002"}) -- 统计workNo为1002的记录数据
2.5.2.分页列表查询
- 【语法】 使用limit()方法来读取指定数量的数据,使用skip()方法,来跳过指定数量的数据.
db.集合名称.find().limit(2).skip(4) -- 分页查询,每页查询2条,从第四条开始
- 【案例】
- 查询一个集合前10条数据
db.douglas.find().limit(10);
-- 前10条数据不要其余的数据返回
db.douglas.find().ip(10);
-- 分页查询:需求 每页2条, 第二页开始的时候:跳过前两条数据
db.douglas.find().skip(0).limit(2) -- 第一页
db.douglas.find().skip(2).limit(2) -- 第二页
2.5.3.排序查询
- 【语法】sort()方法进行排序,sort()方法可以通过指定参数排序的字段,并使用1和-1来指定排序方式.其中1为升序排列,而-1为降序排列;
db.douglas.find().sort({workNo:1}) --查询所有数据,且根据workNo进行升序排列
db.集合名.find().sort(排序方式)
- 【案例】对workNo降序排列,并对点赞量likenum进行升序排列
db.douglas.find().sort({workNo:-1,likenum:1})
- 【注意】
- skip(),limit(),sort()三个放在一起执行的时候,执行的顺序是先sort(),然后skip(),最后是显示的limit(),和命令编写顺序无关;
2.6高级查询
2.6.1.正则的复杂条件查询
- 【模糊查询语法】
db.集合.find({字段:/正则表达式/})
db.douglas.find({name:/正则表达式/})
- 【案例】查询name包含"d"的所有文档
db.douglas.find({name:/d/})
db.douglas.find({name:/^d/}) -- 查询name字段以"d"开头的
2.6.2.比较查询
- 【语法】<,<=,>,>=
db.集合名称.find({field:{$gt:value}}) -- 大于:field > value
db.集合名称.find({field:{$lt:value}}) -- 小于:field < value
db.集合名称.find({field:{$gte:value}}) -- 大于等于: field >= value
db.集合名称.find({field:{$lte:value}}) -- 小于等于: field <= value
db.集合名称.find({field:{$ne:value}}) -- 不等于: field != value
- 【案例】
db.douglas.find(likenum:{$gt:NumberInt(66)}) -- 查询likenum>66的数据
2.6.3.包含查询
- 【语法】使用 i n 包 含 操 作 符 , in包含操作符, in包含操作符,nin不包含操作符
db.douglas.find({workNo:{$in:["1003","1004"]}}) -- 查询集合中workNo包含1003,1004的文档
db.douglas.find({workNo:{$nin:["1003"]}}) -- 查询集合中workNo不包含1003的文档
2.6.4.条件连接查询
- 【and语法】当查询同时满足两个以上条件,需要使用$and操作符将条件关联
$and:[{},{},{}] -- 多个条件格式
db.douglas.find({$and:[{likenum:{$gte:NumberInt(66)}},{likenum:{$lt:NumberInt(100)}}]}) --查询大于等于66 并且小于 100的数据
- 【or语法】两个以上条件之间是或者的关系
$or:[{},{},{}]
db.douglas.find({$or:[{workNo:"1003"},{likenum:{$lt:NumberInt(88)}}]}) --查询workNo=1003或likenum<88的数据
2.7常用命令小结
use.数据库名称 -- 选择切换,创建数据库;
db.集合名称.insertOne({}) -- 新增单条数据
db.集合名称.insertMany({}) -- 批量新增数据
db.集合名称.find({}) -- 全部数据查询
db.集合名称.find({条件}) -- 全部查询/条件查询
db.集合名称.findOne({条件}) -- 查询符合条件的第一条记录
db.集合名称.find({条件}).limit(条数) -- 查询符合条件的前几条记录
db.集合名称.find({条件}).skip(条数) -- 查询符合条件的跳过的记录
db.集合名称.update({条件},{修改后的数据}) -- 根据条件更新整条数据
db.集合名称.update({条件},{$set:{要修改部分的字段:value}}) -- 修改部分字段值
db.集合名称.update({条件},{$inc:{自增字段:自增值}}) -- 修改数据并自增某字段值
db.集合名称.remove({条件}) -- 删除数据
db.集合名称.count({条件}) -- 条件查询
db.集合名称.find({字段名称:/正则表达式/}) -- 模糊查询
db.集合名称.find({字段名称:{$gt:值}}) -- 条件比较运算
db.集合名称.find({字段名:{$in:[值1,值2]}}) -- 包含查询
db.集合名称.find({字段名:{$nin:[值1,值2]}}) -- 非包含查询
db.集合名称.find({$and:[{条件1},{条件2}]}) -- 条件and链接查询
db.集合名称.find({$or:[{条件1},{条件2}]}) -- 条件or链接查询
3.索引
3.1索引概念
- 有无索引区别
- 没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,查询效率非常低。
- 使用索引,限制必须检查的文档数。进行高效查询
- 数据结构
- 索引以易于遍历的形式存储集合数据集的一小部分,存储特定字段或一组字段的值,按字段值排序。
- 索引项的排序支持有效的相等匹配和基于范围的查询操作。
- MongoDB支持使用索引中的排序返回排序结果。
- B-Tree数据结构
3.2索引类型
3.2.1.单字段索引
- MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index);
- 对于单个字段索引和排序操作:
- 索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。
3.2.2.复合索引
- MongoDB支持多个字段的用户定义索引,即复合索引(Compound Index);
- 复合索引中列出的字段顺序具有重要意义。
例如:复合索引由:{userid:1,score:-1}组成,则索引首先按userid正序排序,然后在每个userid的值内,再按score倒序排序。
3.2.3.其它索引
- 地理空间索引(Geospatial Index)
- 为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:
- 返回结果时使用平面几何的二维索引;
- 返回结果时使用球面几何的二维球面索引;
- 为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:
- 文本索引(Text Indexes)
- MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。
- 索引不存储特定语言的停止词(‘the’,‘a’,‘or’),而将集合中的词作为词干,只存储根词。
- 哈希索引(Hashed Indexes)
- 为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。
- 索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。
3.3索引操作
3.3.1.查看索引
- 【语法】
db.集合名称.getIndexes(); -- 返回一个集合中的所有索引的数组。
- 【案例】
db.douglas.getIndexes();
3.3.2.创建索引
- 【语法】
db.集合名称.createIndex(keys,options) -- 指定创建单个索引
db.集合名称.createIndex({userid:1,likenum:-1}) -- 创建复合索引 userid升序索引 likenum降序
- 【案例】
db.douglas.createIndex({userid:1}) -- 创建douglas集合升序索引userid
3.3.3.删除索引
- 【语法】
db.集合名称.dropIndex(index) -- 删除指定索引
db.集合名称.dropIndexes() -- 删除所有索引
- 【案例】
db.douglas.dropIndex({userid:1}) -- 删除douglas集合中userid字段上的升序索引
3.4索引使用
3.4.1.执行计划
- 【语法】
db.集合名称.find(query,options).explain(options)
说明:分析查询性能(Analyze Query Performance)通常使用查询计划(解释计划,Explain Plan)来查看查询的情况;分析查询耗时,是否基于索引查询等。
- 【案例】执行索引查询计划:
db.douglas.find({userid:"1003"}).explain()
3.4.2.涵盖查询
- 当查询条件和查询的投影仅包含所有字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这样的覆盖查询可以非常有效。
- 【案例】
db.douglas.find({userid:"1003"},{userid:1,_id:0})
Index({userid:1}) – 创建douglas集合升序索引userid
#### 3.3.3.删除索引
- 【语法】
```js
db.集合名称.dropIndex(index) -- 删除指定索引
db.集合名称.dropIndexes() -- 删除所有索引
- 【案例】
db.douglas.dropIndex({userid:1}) -- 删除douglas集合中userid字段上的升序索引
3.4索引使用
3.4.1.执行计划
- 【语法】
db.集合名称.find(query,options).explain(options)
说明:分析查询性能(Analyze Query Performance)通常使用查询计划(解释计划,Explain Plan)来查看查询的情况;分析查询耗时,是否基于索引查询等。
- 【案例】执行索引查询计划:
db.douglas.find({userid:"1003"}).explain()
3.4.2.涵盖查询
- 当查询条件和查询的投影仅包含所有字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这样的覆盖查询可以非常有效。
- 【案例】
db.douglas.find({userid:"1003"},{userid:1,_id:0})