一、概念与特点
二、基本常用命令
1. 数据库操作
1.1 选择和创建数据库
代码语言:txt复制use 数据库名称
注:如果数据库不存在,就自动创建。
1.2 查看所有数据库命令
代码语言:txt复制1. show dbs
2. show databases
* 两者任选其一即可
注意:在MongDB中,集合只有在内容插入后才会创建。
代码语言:txt复制 也就是说,创建集合(数据表)后,需要再插入数据,集合才会真正创建。
1.3 查看当前使用的数据库
代码语言:txt复制db
注:MongDB中默认的数据库为test,如果你没有选择数据库,集合将默认存放在test数据库中
1.4 删除数据库
代码语言:txt复制db.dropDatabase()
注:主要用于删除已经持久化的数据库
* 数据库名命名规则
数据库名可以满足以下条件的任意UTF-8字符串:
- 不能是空字符串
- 不得含有空格、. 、$、/、和 (空字符串)
- 应全部小写
- 最多64字节
* MongDB保留的数据库的作用
- admin:
- 从权限的角度来看,这是“root”数据库
- 如果将一个用户添加到这个数据库中,这个用户将继承所有数据库的权限
- 一些特定的服务端命令也只能从这个数据库运行,比如列出所有数据库或者关闭任意服务器
- local:
- 在这个数据库中的数据,永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config:
- 当mongDB用于分片设置时,config数据库在内保使用,用于保存分片的相关信息。
2. 集合操作
集合,即数据表。
其可以显示的创建,也可以隐式的创建。
2.1 显示创建集合
代码语言:txt复制语法: db.createCollection(数据库名称)
eg: db.createCollection("mycollection")
2.2 隐式创建集合
当向一个集合中插入一个文档的时候,如何集合不存在,则会自动创建集合。(详见文档插入)
2.3 查看当前数据库中的表
代码语言:txt复制* 1. show collections
* 2. show tables
两者任选其一即可
2.4 删除集合
代码语言:txt复制* 1. db.collection.drop()
* 2. db.集合名称.drop()
任选其一即可
* eg: db.mycollection.drop()
注:如果成功删除集合,则返回true,否则返回false
3. 文档的CRUD(增删改查)
文档(document)的数据结构(BSON)和 JSON 基本一样。
3.1 插入文档
3.1.1 单个文档的插入
- 使用insert()或者save()方法向集合中插入文档
db.collection.insert(
<document or array of documents>,
{
writeConcern: <document>,
ordered: <boolean>
}
)
- 参数:
Parameter | Type | Description |
---|---|---|
document | document or array | 要插入到集合中的文档或文档数组。((json格式) |
writeConcern | document | Optional. A document expressing the write concern. Omit to use the default write concern.See Write Concern.Do not explicitly set the write concern for the operation if run in a transaction. To use write concern with transactions, see Transactions and Write Concern. |
ordered | boolean | 可选。如果为真,则按顺序插入数组中的文档,如果其中一个文档出现错误,MongoDB将返回而不处理数组中的其余文档。如果为假,则执行无序插入,如果其中一个文档出现错误,则继续处理数组中的主文档。在版本2.6 中默认为true |
- 示例:
db.comment.insert({
"articleid":"100000",
"content":"今天天气真好,阳光明媚",
"userid":"1001",
"nickname":"Rose",
"createdatetime":new Date(),
"likenum":NumberInt(10),
"state":null
})
- 提示:
- comment集合如果不存在,则会隐式创建
- mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了
- 插入当前日期使用 new Date()
- 插入的数据没有指定 _id ,会自动生成主键值
- 如果某字段没值,可以赋值为null,或不写该字段。
- 执行后,如果插入成功,则会返回如下:
WriteResult({ "nInserted" : 1 })
- 注意:
- 文档中的键/值对是有序的
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB区分类型和大小写
- MongoDB的文档不能有重复的键
- 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符
3.1.2 批量插入
语法:
代码语言:txt复制db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
示例:
代码语言:txt复制db.comment.insertMany([
{
"_id":"1",
"articleid":"100001",
"content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。",
"userid":"1002",
"nickname":"相忘于江湖",
"createdatetime":new Date("2019-08- 05T22:08:15.522Z"),
"likenum":NumberInt(1000),
"state":"1"
}, {
"_id":"2",
"articleid":"100001",
"content":"我夏天空腹喝凉开水,冬天喝温开水",
"userid":"1005",
"nickname":"伊人憔 悴",
"createdatetime":new Date("2019-08-05T23:58:51.485Z"),
"likenum":NumberInt(888),
"state":"1"
}, {
"_id":"3",
"articleid":"100001",
"content":"我一直喝凉开水,冬天夏天都喝。",
"userid":"1004","nickname":"杰克船 长",
"createdatetime":new Date("2019-08-06T01:05:06.321Z"),
"likenum":NumberInt(666),
"state":"1"
},
]);
提示:
- 插入时指定了 _id ,则主键就是该值。
- 如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚掉。
- 因为批量插入由于数据较多容易出现失败,因此,可以使用try catch进行异常捕捉处理,测试的时候可以不处理。如:
try {
代码语言:txt复制 db.comment.insertMany([
代码语言:txt复制 {
代码语言:txt复制 "_id":"1",
代码语言:txt复制 "articleid":"100001",
代码语言:txt复制 "content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。",
代码语言:txt复制 "userid":"1002",
代码语言:txt复制 "nickname":"相忘于江湖",
代码语言:txt复制 "createdatetime":new Date("2019-08- 05T22:08:15.522Z"),
代码语言:txt复制 "likenum":NumberInt(1000),
代码语言:txt复制 "state":"1"
代码语言:txt复制 }, {
代码语言:txt复制 "_id":"2",
代码语言:txt复制 "articleid":"100001",
代码语言:txt复制 "content":"我夏天空腹喝凉开水,冬天喝温开水",
代码语言:txt复制 "userid":"1005",
代码语言:txt复制 "nickname":"伊人憔 悴",
代码语言:txt复制 "createdatetime":new Date("2019-08-05T23:58:51.485Z"),
代码语言:txt复制 "likenum":NumberInt(888),
代码语言:txt复制 "state":"1"
代码语言:txt复制 }, {
代码语言:txt复制 "_id":"3",
代码语言:txt复制 "articleid":"100001",
代码语言:txt复制 "content":"我一直喝凉开水,冬天夏天都喝。",
代码语言:txt复制 "userid":"1004","nickname":"杰克船 长",
代码语言:txt复制 "createdatetime":new Date("2019-08-06T01:05:06.321Z"),
代码语言:txt复制 "likenum":NumberInt(666),
代码语言:txt复制 "state":"1"
代码语言:txt复制 },
]);
} catch (e) {
代码语言:txt复制 print (e);
}
代码语言:txt复制
3.2 文档的查询
代码语言:txt复制db.collection.find(<query>, [projection])
参数:
Parameter | Type | Description |
---|---|---|
query | document | 可选。使用查询运算符指定选择筛选器。若要返回集合中的所有文档,请省略此参数或传递空文档( {} ) |
projection | document | 可选。指定要在与查询筛选器匹配的文档中返回的字段(投影)。若要返回匹配文档中的所有字段, |
3.2.1 查询所有
代码语言:txt复制* 1. db.comment.find()
* 2. db.comment.find({})
任选其一即可
我们会发现每条文档都有一个叫 _id 的字段,这个相当于关系型数据库中表的主键,当我们在插入文档记录时没有指定该字段,MongDB会自动创建,其类型是ObjectID类型。
3.2.2 条件查询
代码语言:txt复制db.comment.find({userid:'1003'})
如果我们只想返回符合条件的第一条数据,可以使用findOne命令来实现
代码语言:txt复制db.comment.findOne({userid:'1003'})
3.2.3 投影查询
即:只返回指定字段的结果
示例:只返回 name和age
代码语言:txt复制db.comment.find({userid:'1003'},{name:1,age:1})
注:默认 _id 会显示
但是,如果不想显示 _id,即:
代码语言:txt复制db.comment.find({userid:"1003"},{name:1,age:1,_id:0})
再例如,查询所有数据,但只显示 name 和 age
代码语言:txt复制db.comment.find({},{name:1,age:1,_id:0})
3.3 文档的更新
语法:
代码语言:txt复制* 1. db.collection.update(query, update, options)
* 2. db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2
} )
参数:
Parameter | Type | Description |
---|---|---|
query | document | 更新的选择条件。可以使用与fifind()方法中相同的查询选择器,类似sql update查询内where后面的。。在3.0版中进行了更改:当使用upsert:true执行update()时,如果查询使用点表示法在_id字段上指定条件,则MongoDB将拒绝插入新文档。 |
update | document or pipeline | 要应用的修改。该值可以是:包含更新运算符表达式的文档,或仅包含:对的替换文档,或在MongoDB 4.2中启动聚合管道。 |
upsert | boolean | 可选。如果设置为true,则在没有与查询条件匹配的文档时创建新文档。默认值为false,如果找不到匹配项,则不会插入新文档。 |
multi | boolean | 可选。如果设置为true,则更新符合查询条件的多个文档。如果设置为false,则更新一个文档。默认值为false。 |
writeConcern | document | 可选。表示写问题的文档。抛出异常的级别。 |
collation | document | 可选。指定要用于操作的校对规则。校对规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音标记的规则。(详百度) |
arrayFilters | array | 可选。一个筛选文档数组,用于确定要为数组字段上的更新操作修改哪些数组元素。 |
hint | Document or String | 可选。指定用于支持查询谓词的索引的文档或字符串。该选项可以采用索引规范文档或索引名称字符串。如果指定的索引不存在,则说明操作错误。例如,请参阅版本4中的“为更新操作指定提示。 |
3.3.1 覆盖的修改
eg: 修改_id为1的记录,点赞量为1001
代码语言:txt复制db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
执行后,我们会发现,这条文档除了likenum字段其它字段都不见了
3.3.2 局部修改
要使用修改器$set来实现
修改_id为2的记录,浏览量为889
代码语言:txt复制db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}})
3.3.3 批量修改
更新所有用户为 1003 的用户的昵称
代码语言:txt复制* 默认只修改第一条数据
db.comment.update({userid:"1003"},{$set:{name:"哈哈"}})
* 修改所有符合条件的数据
db.comment.update({userid:"1003"},{$set:{name:"哈哈哈"}},{multi:true})
提示:如果不加后面的参数,则只更新符合条件的第一条记录
3.3.4 列值增长的修改
如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现
需求:对3号数据的点赞数,每次递增1
代码语言:txt复制db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
3.4 文档的删除
代码语言:txt复制db.集合名称.remove(条件)
将数据全部删除
代码语言:txt复制db.comment.remove({})
如果只删除 id为 1的记录,如下:
代码语言:txt复制db.comment.remove{id:"1"}
3.5 统计查询
代码语言:txt复制db.collection.count(query,options)
参数:
Parameter | Type | Description |
---|---|---|
query | document | 查询选择条件。 |
options | document | 可选。用于修改计数的额外选项。 |
示例:
3.5.1 统计所有记录数
统计comment集合的所有记录数
代码语言:txt复制db.comment.count()
3.5.2 按条件统计记录数
统计id为1003的所有的记录数
代码语言:txt复制db.comment.count({id:"1003"})
3.6 分页查询
- 使用limit()方法来读取指定数量的数据
- 使用skip()方法来跳过指定数量的数据
* 基本语法
db.集合名称.find().limit(number).skip(number)
- 如果想返回指定条数的记录,可以在调用limit来实现,默认值20
db.comment.find().limit(3)
- 如果不想返回前几条记录数,可以用skip实现,默认值0
db.comment.find().skip(3)
- 分页查询:需求:每页2个,第二页开始:跳过前两条数据,接着值显示3和4条数据
//第一页
db.comment.find().skip(0).limit(2)
//第二页
db.comment.find().skip(2).limit(2)
//第三页
db.comment.find().skip(4).limit(2)
3.7 排序查询
sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。
代码语言:txt复制* 语法:
* 1. db.集合名称.find().sort({KEY:1})
* 2. db.集合名称.find().sort(排序方式)
任选其一即可
示例:
对userid降序排列,并对访问量进行升序排列
代码语言:txt复制db.comment.find().sort({userid:-1,likenum:1})
注:
skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit(),和命令编写顺序无关。
3.8 模糊查询(正则表达式)
MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:
代码语言:txt复制* 1. db.collection.find({field:/正则表达式/})
* 2. db.集合.find({字段:/正则表达式/})
提示:正则表达式是js的语法,直接量的写法。
例如,我要查询评论内容包含“开水”的所有文档,代码如下:
代码语言:txt复制db.comment.find({content:/开水/})
如果要查询评论的内容中以“专家”开头的,代码如下:
代码语言:txt复制db.comment.find({content:/^专家/})
3.9 比较查询
<, <=, >, >= 这个操作符也是很常用的,格式如下:
代码语言:txt复制// 大于: field > value
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 }})
示例:查询评论点赞数量大于700的记录
代码语言:txt复制db.comment.find(likenum:{$gt:Number(700)})
3.10 包含查询
包含使用$in操作符。
示例:查询评论的集合中userid字段包含1003或1004的文档
代码语言:txt复制db.comment.find({userid:{$in:["1003","1004"}})
不包含使用$nin操作符。
示例:查询评论集合中userid字段不包含1003和1004的文档
代码语言:txt复制db.comment.find({userid:{$nin:["1003","1004"]}})
3.11 条件连接查询
如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相 当于SQL的and) 格式为:
代码语言:txt复制$and:[ { },{ },{ } ]
示例:查询评论集合中likenum大于等于700 并且小于2000的文档:
代码语言:txt复制db.comment.find($and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}])
如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面 and的使用方式相同 格式为:
代码语言:txt复制$or:[ { },{ },{ } ]
示例:查询评论集合中userid为1003,或者点赞数小于1000的文档记录
代码语言:txt复制db.comment.find($or:[{userid:"1003"},{likenum:{$lt:1000} }])
* 文档键命名规范
- 键不能含有 (空字符)。这个字符用来表示键的结尾。
- .和$有特别的意义,只有在特定环境下才能使用。
- 以下划线"_"开头的键是保留的(不是严格要求的)。
三、索引
1. 概述
MongoDB索引使用的是B树数据结构,确切的说是 B-Tree,MySQL使用的是 B Tree。
2. 索引的类型
2.1 单字段索引
MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引。
对于单个字段索引和排序规则,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。
2.2 复合索引
MongoDB还支持多个字段的用户定义索引,即符合索引。
复合索引中列出的字段顺序具有重要意义。例如:如果复合索引由{userid:1,score:-1}组成,则索引首先按userid正序排序,然后在每个userid的值内,再在按score倒序排序。
2.3 地理空间索引
为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。
2.4 文本索引
MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),而将集合中的词作为词干,只存储根词。
2.5 哈希索引
为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。
3. 索引的管理操作
3.1 查看索引
返回一个集合中的所有索引的数组
语法:
代码语言:txt复制db.collection.getIndexes()
默认 _id 索引:
MongoDB在创建=集合的过程中,在_id字段上创建一个唯一的索引,默认名字为 _id,该索引可防止客户端插入两个具有相同值的文档,您不能在 _id字段上删除此索引。
注:该索引是唯一索引,因此值不能重复,即_id值不能重复的。在分片集群中,通常使用 _id作为片键。
3.2 创建索引
在集合上创建索引
代码语言:txt复制db.collection.createIndex(keys,options)
参数:
Parameter | Type | Description |
---|---|---|
keys | document | 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段上的升序索引,请指定值1;对于降序索引,请指定值-1。比如: {字段:1或-1} ,其中1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。另外,MongoDB支持几种不同的索引类型,包括文本、地理空间和哈希索引。 |
options | document | 可选。包含一组控制索引创建的选项的文档。有关详细信息,请参见选项详情列表。 |
options(更多选项)列表:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加"background" 可选参数。 "background" 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 3.0 **版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为language. |
提示:
注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex() ,之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。
示例:
代码语言:txt复制db.comment.createIndex({userid:1})
参数说明:
按升序创建索引
该索引名为:
userid_1
复合索引:
代码语言:txt复制对userid和name同时建立符合索引
db.comment.createIndex({userid:1,name:-1})
3.3 删除索引
可以删除指定的索引,或者删除所有索引
3.3.1 删除指定索引
代码语言:txt复制db.collection.dropIndex(index)
参数说明:
index:指定要删除的索引。可以通过索引名称或索引规范文档指定索引。若要删除文本索引,请指定索引名称。
示例:
删除comment集合中的userid字段上的升序索引
代码语言:txt复制db.comment.dropIndex({userid:1})
3.3.2 删除所有索引
代码语言:txt复制db.collection.dropIndexes()
注:_id 的字段的索引是无法删除的,只能删除非 _id 字段的索引。
4. 索引的使用
4.1 执行计划
分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。
语法:
代码语言:txt复制db.collection.find(query,options).explain(options)
示例:
查看根据userid查询数据的情况:
代码语言:txt复制db.collection.find({userid:"1003"}).explain()
注: "stage" : "COLLSCAN", 表示全集合扫描
代码语言:txt复制// 对userid建立索引
>db.comment.createIndex({userid:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
// 再次查看执行计划
> db.comment.find({userid:"1013"}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "articledb.comment",
"indexFilterSet" : false,
"parsedQuery" : {
"userid" : {
"$eq" : "1013"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"userid" : 1
},
"indexName" : "userid_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"userid" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"userid" : [
"["1013", "1013"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "WINDOWS-7B2N9FU",
"port" : 27017,
"version" : "3.4.24-3-g78e64a697a",
"gitVersion" : "78e64a697a46e1fa7f85d1c52507ffbbfe30a713"
},
"ok" : 1
}
4.2 涵盖的查询
当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。
代码语言:txt复制> db.comment.find({userid:"1003"},{userid:1,_id:0})
{ "userid" : "1003" }
{ "userid" : "1003" }
> db.comment.find({userid:"1003"},{userid:1,_id:0}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "articledb.comment",
"indexFilterSet" : false,
"parsedQuery" : {
"userid" : {
"$eq" : "1003"
}
},
"winningPlan" : {
"stage" : "PROJECTION",
"transformBy" : {
"userid" : 1,
"_id" : 0
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"userid" : 1
},
"indexName" : "userid_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"userid" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"userid" : [
"["1003", "1003"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "WINDOWS-7B2N9FU",
"port" : 27017,
"version" : "3.4.24-3-g78e64a697a",
"gitVersion" : "78e64a697a46e1fa7f85d1c52507ffbbfe30a713"
},
"ok" : 1
}