数据库操作
创建
- 选择和创建数据库的语法格式: 如果数据库不存在则自动创建,例如,以下语句创建 spitdb 数据库:
use spitdb
查看
- 查看当前正在使用的数据库命令
show dbs
或
show databases
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
mydb 0.000GB
- 查看有权限查看的所有的数据库命令
db
> db
test
MongoDB 中默认的数据库为 test,如果你没有选择数据库,集合将存放在 test 数据库中。
注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
另外: 数据库名可以是满足以下条件的任意UTF-8字符串。
- 不能是空字符串("")。
- 不得含有’ ‘(空格)、.、$、/、\和\0 (空字符)。
- 应全部小写。
- 最多64字节。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,该用户自动继承所有数据库的权限。 一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
删除
- 数据库的删除 MongoDB 删除数据库的语法格式如下:
db.dropDatabase()
db.dropDatabase()
{ ok: 1, dropped: 'mydb' }
集合操作
集合创建
- 集合的隐式创建 当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合。
- 集合的显式创建(了解)
基本语法格式:
db.createCollection(name)
name: 要创建的集合名称
集合的命名规范:
- 集合名不能是空字符串""。
- 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
- 集合名不能以"system.“开头,这是为系统集合保留的前缀。
- 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
删除集合
集合删除语法格式如下:
db.collection.drop()
或
db.集合.drop()
db.comment.drop()
true
如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
文档(document)的操作
文档(document)的数据结构和 JSON 基本一样,所有存储在集合中的数据都是 BSON 格式。
插入
- 单条文档插入
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({"_id":"0","articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date(),"likenum":NumberInt(10),"state":null})
{ acknowledged: true, insertedIds: { '0': '0' } }
1)comment集合如果不存在,则会隐式创建
2)mongo中的数字,默认情况下是double类型,如果要存整型,必须使用函数NumberInt(整型数字),否则取出来就有问题了。
3)插入当前日期使用 new Date()
4)插入的数据如果没有指定 _id ,会自动生成主键值
5)如果某字段没值,可以赋值为null,或不写该字段。
注意:
- 文档中的键/值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB区分类型和大小写。
- MongoDB的文档不能有重复的键。
- 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
文档键命名规范: 键不能含有\0 (空字符)。这个字符用来表示键的结尾。 .和$有特别的意义,只有在特定环境下才能使用。 以下划线”_“开头的键是保留的(不是严格要求的)。
- 多条文档插入
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
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":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},{"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}]);
{ acknowledged: true,
insertedIds: { '0': '1', '1': '2', '2': '3', '3': '4', '4': '5' } }
1)插入时指定了 _id ,则主键就是该值。 2)如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚掉。 3)因为批量插入由于数据较多容易出现失败,因此,可以使用try catch进行异常捕捉处理,测试的时候可以不处理。
查询
查询数据的语法格式如下:
db.collection.find(<query>, [projection])
Parameter | Type | Description |
---|---|---|
query | document | 可选。使用查询运算符指定选择筛选器。若要返回集合中的所有文档,请省略此参数或传递空文档( {} ) |
projection | document | 可选。指定要在与查询筛选器匹配的文档中返回的字段(投影)。若要返回匹配文档中的所有字段,请省略此参数。 |
查询所有
db.comment.find() #或find({}) { _id: '0', articleid: '100000', content: '今天天气真好,阳光明媚', userid: '1001', nickname: 'Rose', createdatetime: 2022-01-21T12:57:49.081Z, likenum: 10, state: null } { _id: '1', articleid: '100001', content: '我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。', userid: '1002', nickname: '相忘于江湖', createdatetime: 2019-08-05T22:08:15.522Z, likenum: 1000, state: '1' } { _id: '2', articleid: '100001', content: '我夏天空腹喝凉开水,冬天喝温开水', userid: '1005', nickname: '伊人憔悴', createdatetime: 2019-08-05T23:58:51.485Z, likenum: 888, state: '1' } { _id: '3', articleid: '100001', ......
查询某些
db.comment.find({},{content:1,nikename:1}) #注意:1
{ _id: '0', content: '今天天气真好,阳光明媚' }
{ _id: '1', content: '我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。' }
{ _id: '2', content: '我夏天空腹喝凉开水,冬天喝温开水' }
{ _id: '3', content: '我一直喝凉开水,冬天夏天都喝。' }
{ _id: '4', content: '专家说不能空腹吃饭,影响健康。' }
{ _id: '5', content: '研究表明,刚烧开的水千万不能喝,因为烫嘴。' }
- 条件查询
db.comment.find({userid:'1004'},{content:1,nikename:1})
{ _id: '3', content: '我一直喝凉开水,冬天夏天都喝。' }
- 去除索引
db.comment.find({},{content:1,nikename:1,_id:0}) **#_id:0**
{ content: '今天天气真好,阳光明媚' }
{ content: '我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。' }
{ content: '我夏天空腹喝凉开水,冬天喝温开水' }
{ content: '我一直喝凉开水,冬天夏天都喝。' }
{ content: '专家说不能空腹吃饭,影响健康。' }
{ content: '研究表明,刚烧开的水千万不能喝,因为烫嘴。' }
#记录名写错,系统不会提醒报错,如上面,nickname写成了nikename
- 统计查询
db.collection.count(query, options)
db.comment.find().count()
6
db.comment.countDocuments({userid:'1003'})
2
- 分页列表查询
使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据
db.comment.find({},{userid:1,nicknam:1,likenum:1}).limit(2)
{ _id: '0', userid: '1001', likenum: 10 }
{ _id: '1', userid: '1002', likenum: 1000 }
db.comment.find({},{userid:1,nicknam:1,likenum:1}).limit(2).skip(2)
{ _id: '2', userid: '1005', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
- 排序
db.COLLECTION_NAME.find().sort({KEY:1})
或
db.集合名称.find().sort(排序方式)
> db.comment.find({},{userid:1,nickname:1}).sort({nickname:1})
{ "_id" : "0", "userid" : "1001", "nickname" : "Rose" }
{ "_id" : "2", "userid" : "1005", "nickname" : "伊人憔悴" }
{ "_id" : "4", "userid" : "1003", "nickname" : "凯撒" }
{ "_id" : "5", "userid" : "1003", "nickname" : "凯撒" }
{ "_id" : "3", "userid" : "1004", "nickname" : "杰克船长" }
{ "_id" : "1", "userid" : "1002", "nickname" : "相忘于江湖" }
复杂条件查询
- 正则表达式
MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:
db.collection.find({field:/正则表达式/})
或
db.集合.find({字段:/正则表达式/})
包含:/…/
db.comment.find({content:/开水/})
{ _id: '2',
articleid: '100001',
content: '我夏天空腹喝凉开水,冬天喝温开水',
userid: '1005',
nickname: '伊人憔悴',
createdatetime: 2019-08-05T23:58:51.485Z,
likenum: 888,
state: '1' }
{ _id: '3',
articleid: '100001',
content: '我一直喝凉开水,冬天夏天都喝。',
userid: '1004',
nickname: '杰克船长',
createdatetime: 2019-08-06T01:05:06.321Z,
likenum: 666,
state: '1' }
^开头
db.comment.find({content:/^我/})
{ _id: '1',
articleid: '100001',
content: '我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。',
userid: '1002',
nickname: '相忘于江湖',
createdatetime: 2019-08-05T22:08:15.522Z,
likenum: 1000,
state: '1' }
{ _id: '2',
articleid: '100001',
content: '我夏天空腹喝凉开水,冬天喝温开水',
userid: '1005',
nickname: '伊人憔悴',
createdatetime: 2019-08-05T23:58:51.485Z,
likenum: 888,
state: '1' }
{ _id: '3',
articleid: '100001',
content: '我一直喝凉开水,冬天夏天都喝。',
userid: '1004',
nickname: '杰克船长',
createdatetime: 2019-08-06T01:05:06.321Z,
likenum: 666,
state: '1' }
db.comment.find({content:/开水/},{userid:1,nickname:1})
{ _id: '2', userid: '1005', nickname: '伊人憔悴' }
{ _id: '3', userid: '1004', nickname: '杰克船长' }
- 包含查询 包含使用$in操作符。
db.comment.find({userid:{$in:['1003','1004']}})
{ _id: '3',
articleid: '100001',
content: '我一直喝凉开水,冬天夏天都喝。',
userid: '1004',
nickname: '杰克船长',
createdatetime: 2019-08-06T01:05:06.321Z,
likenum: 666,
state: '1' }
{ _id: '4',
articleid: '100001',
content: '专家说不能空腹吃饭,影响健康。',
userid: '1003',
nickname: '凯撒',
createdatetime: 2019-08-06T08:18:35.288Z,
likenum: 2000,
state: '1' }
{ _id: '5',
articleid: '100001',
content: '研究表明,刚烧开的水千万不能喝,因为烫嘴。',
userid: '1003',
nickname: '凯撒',
createdatetime: 2019-08-06T11:01:02.521Z,
likenum: 3000,
state: '1' }
db.comment.find({userid:{$in:['1003','1004']}},{userid:1,nickname:1})
{ _id: '3', userid: '1004', nickname: '杰克船长' }
{ _id: '4', userid: '1003', nickname: '凯撒' }
{ _id: '5', userid: '1003', nickname: '凯撒' }
- 条件连接查询
$and,$or
db.comment.find({$and:[{content:/开水/},{userid:'1004'}]},{userid:1,nickname:1,content:1})
{ _id: '3',
content: '我一直喝凉开水,冬天夏天都喝。',
userid: '1004',
nickname: '杰克船长' }
更新
语法
db.collection.update(query, update, options)
//或
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 | 更新的选择条件。可以使用与find()方法中相同的查询选择器,类似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 | 可选。指定要用于操作的校对规则。校对规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音标记的规则。校对规则选项具有以下语法: |
校对规则: | ||
{区域设置:,caseLevel:,caseFirst:,强度:,numericordering:,替代:,最大变量:,向后:} | ||
指定校对规则时,区域设置字段是必需的;所有其他校对规则字段都是可选的。有关字段的说明,请参阅校对规则文档。如果未指定校对规则,但集合具有默认校对规则(请参见db.createCollection()),则该操作将使用为集合指定的校对规则。 | ||
如果没有为集合或操作指定校对规则,MongoDB将使用本中使用的简单二进制比较进行字符串比较。不能为一个操作指定多个校对规则。例如,不能为每个字段指定不同的校对规则,或者如果使用排序执行查找,则不能将一个校对规则用于查找,另一个校对规则用于排序。3.4版新增。 | ||
arrayFilters | array | 可选。一个筛选文档数组,用于确定要为数组字段上的更新操作修改哪些数组元素。 |
hint | Document or string | 可选。指定用于支持查询谓词的索引的文档或字符串。该选项可以采用索引规范文档或索引名称字符串。如果指定的索引不存在,则说明操作错误。例如,请参阅版本4中的“为更新操作指定提示。 |
- 覆盖
Mongodb Compass 5会对此报错
db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
MongoInvalidArgumentError: Update document requires atomic operators
......
atomic operators:
$set 用来指定一个键并更新键值,若键不存在并创建。 { $set : { field : value } } $unset 用来删除一个键。 { $unset : { field : 1} } $inc $inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。 { $inc : { field : value } } $push { $push : { field : value } } 把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。 ……
换到shell环境:
> db.comment.update({likenum:888},{userid:'1009'})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.comment.find()
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : "2", "userid" : "1009" }
{ "_id" : "3", "articleid" : "100001", "content" :
......
执行成功,但是,document中只有update的userid,其他都没有了,这是一种覆盖模式。
- $set局部修改
db.comment.update({userid:'1003'},{$set:{likenum:999}})
{ acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0 }
db.comment.find({},{userid:1,likenum:1})
{ _id: '0', userid: '1001', likenum: 10 }
{ _id: '1', userid: '1002', likenum: 1000 }
{ _id: '2', userid: '1100', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
{ _id: '4', userid: '1003', likenum: 999 }
{ _id: '5', userid: '1003', likenum: 3000 }
上面的例子userid:1003有两条,如果都要改,加上multi:true
db.comment.update({userid:'1003'},{$set:{likenum:777}},{multi:true})
{ acknowledged: true,
insertedId: null,
matchedCount: 2,
modifiedCount: 2,
upsertedCount: 0 }
db.comment.find({},{userid:1,likenum:1})
{ _id: '0', userid: '1001', likenum: 10 }
{ _id: '1', userid: '1002', likenum: 1000 }
{ _id: '2', userid: '1100', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
{ _id: '4', userid: '1003', likenum: 777 }
{ _id: '5', userid: '1003', likenum: 777 }
- 对某个值自增
db.comment.update({userid:'1001'},{$inc:{likenum:1}})
{ acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0 }
db.comment.find({},{userid:1,likenum:1})
{ _id: '0', userid: '1001', likenum: 11 }
{ _id: '1', userid: '1002', likenum: 1000 }
{ _id: '2', userid: '1100', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
{ _id: '4', userid: '1003', likenum: 777 }
{ _id: '5', userid: '1003', likenum: 777 }
删除
db.集合名称.remove(条件)
db.comment.remove({_id:'4'})
'DeprecationWarning: Collection.remove() is deprecated. Use deleteOne, deleteMany, findOneAndDelete, or bulkWrite.'
{ acknowledged: true, deletedCount: 1 }
db.comment.find({},{userid:1,likenum:1})
{ _id: '0', userid: '1001', likenum: 11 }
{ _id: '1', userid: '1002', likenum: 1000 }
{ _id: '2', userid: '1100', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
{ _id: '5', userid: '1003', likenum: 777 }
提示即将弃用,尝试新的命令
db.comment.findOneAndDelete({_id:'0'})
{ _id: '0',
articleid: '100000',
content: '今天天气真好,阳光明媚',
userid: '1001',
nickname: 'Rose',
createdatetime: 2022-01-21T12:57:49.081Z,
likenum: 11,
state: null }
db.comment.find({},{userid:1,likenum:1})
{ _id: '1', userid: '1002', likenum: 1000 }
{ _id: '2', userid: '1100', likenum: 888 }
{ _id: '3', userid: '1004', likenum: 666 }
{ _id: '5', userid: '1003', likenum: 777 }
索引
如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。 索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排 序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。
官网文档: Indexes
MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)
索引的类型
- 单字段索引 MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。
- 复合索引 MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。
- 其他索引 地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(Hashed Indexes)。
索引的管理操作
- 索引的查看
db.collection.getIndexes()
db.comment.getIndexes()#默认索引
[ { v: 2, key: { _id: 1 }, name: '_id_' } ]
v-version
- 在集合上创建索引
(1)单字段索引
db.collection.createIndex(keys, options)
db.comment.createIndex({userid:1})
'userid_1'
db.comment.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { userid: 1 }, name: 'userid_1' }
]
创建了userid的索引
keys :document 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。 对于字段上的升序索引,请指定值1;对于降序索引,请指定值-1。比如: {字段:1或-1} ,其中1 为指定按升序创建索引,如想按降序来创建索引指定为 -1 即可。 另外,MongoDB支持几种不同的索引类型,包括文本、地理空间和哈希索引。
options列表:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加"background” 可选参数。 “background” 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为language. |
(2)复合索引:对 userid 和 nickname 同时建立复合(Compound)索引:
db.comment.createIndex({nickname:1,userid:-1})
'nickname_1_userid_-1'
db.comment.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { userid: 1 }, name: 'userid_1' },
{
v: 2,
key: { nickname: 1, userid: -1 },
name: 'nickname_1_userid_-1'
}
]
- 删除索引
(1)删除某个索引
db.comment.dropIndex({userid:1}) #按字段删除
{ nIndexesWas: 3, ok: 1 }
db.comment.getIndexes()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{
v: 2,
key: { nickname: 1, userid: -1 },
name: 'nickname_1_userid_-1'
}
]
db.comment.dropIndex('nickname_1_userid_-1')#按名字删除,不使用{}
{ nIndexesWas: 2, ok: 1 }
(2)删除全部用户索引
db.comment.dropIndexes()
{
nIndexesWas: 3,
msg: 'non-_id indexes dropped for collection',
ok: 1
}
db.comment.getIndexes()
[ { v: 2, key: { _id: 1 }, name: '_id_' } ]#系统索引不会被删除
索引的使用
- 执行计划 分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。 语法:
db.collection.find(query,options).explain(options)
示例:
db.comment.find({userid:'1003'}).explain()
{ explainVersion: '1',
queryPlanner:
{ namespace: 'etaondb.comment',
indexFilterSet: false,
parsedQuery: { userid: { '$eq': '1003' } },
maxIndexedOrSolutionsReached: false,
maxIndexedAndSolutionsReached: false,
maxScansToExplodeReached: false,
winningPlan:
{ stage: 'COLLSCAN',
filter: { userid: { '$eq': '1003' } },
direction: 'forward' },
rejectedPlans: [] },
command: { find: 'comment', filter: { userid: '1003' }, '$db': 'etaondb' },
serverInfo:
{ host: 'Alma',
port: 27017,
version: '5.0.5',
gitVersion: 'd65fd89df3fc039b5c55933c0f71d647a54510ae' },
serverParameters:
{ internalQueryFacetBufferSizeBytes: 104857600,
internalQueryFacetMaxOutputDocSizeBytes: 104857600,
internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
internalDocumentSourceGroupMaxMemoryBytes: 104857600,
internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
internalQueryProhibitBlockingMergeOnMongoS: 0,
internalQueryMaxAddToSetBytes: 104857600,
internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600 },
ok: 1 }
增加userid的index后:
db.comment.createIndex({userid:1})
'userid_1'
db.comment.find({userid:'1003'}).explain()
{ explainVersion: '1',
queryPlanner:
{ namespace: 'etaondb.comment',
indexFilterSet: false,
parsedQuery: { userid: { '$eq': '1003' } },
maxIndexedOrSolutionsReached: false,
maxIndexedAndSolutionsReached: false,
maxScansToExplodeReached: false,
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: [ '["1003", "1003"]' ] } } },
rejectedPlans: [] },
command: { find: 'comment', filter: { userid: '1003' }, '$db': 'etaondb' },
serverInfo:
{ host: 'Alma',
port: 27017,
version: '5.0.5',
gitVersion: 'd65fd89df3fc039b5c55933c0f71d647a54510ae' },
serverParameters:
{ internalQueryFacetBufferSizeBytes: 104857600,
internalQueryFacetMaxOutputDocSizeBytes: 104857600,
internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
internalDocumentSourceGroupMaxMemoryBytes: 104857600,
internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
internalQueryProhibitBlockingMergeOnMongoS: 0,
internalQueryMaxAddToSetBytes: 104857600,
internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600 },
ok: 1 }
上面的例子可以看到查询方式的变化:
winningPlan: { stage: ‘COLLSCAN’, filter: { userid: { ‘$eq’: ‘1003’ } }, 变成: winningPlan: { stage: ‘FETCH’, inputStage: { stage: ‘IXSCAN’, keyPattern: { userid: 1 }, indexName: ‘userid_1’,
COLLSCAN表示全集扫描 FETCH抓取 IXSCAN扫描Index
从compass看:
Documents Examined:6 检查了6次,即所有6条docments
而使用了index:userid后
检查次数变成了2,效率提高了;使用的方式和命令行的情况一致
- 涵盖的查询 Covered Queries 当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以非常有效。
上面的例子进行查询
不查看_id,显示documents检查为0
> db.comment.find({userid:1,_id:0}).explain()
{
"explainVersion" : "1",
"queryPlanner" : {
"namespace" : "etaondb.comment",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"_id" : {
"$eq" : 0
}
},
{
"userid" : {
"$eq" : 1
}
}
]
},
"queryHash" : "B3109953",
"planCacheKey" : "349BB72E",
"maxIndexedOrSolutionsReached" : false,
"maxIndexedAndSolutionsReached" : false,
"maxScansToExplodeReached" : false,
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"userid" : {
"$eq" : 1
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"_id" : 1
},
"indexName" : "_id_",
"isMultiKey" : false,
"multiKeyPaths" : {
"_id" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_id" : [
"[0.0, 0.0]"
]
}
}
},
"rejectedPlans" : [ ]
},
"command" : {
"find" : "comment",
"filter" : {
"userid" : 1,
"_id" : 0
},
"$db" : "etaondb"
},
"serverInfo" : {
"host" : "Alma",
"port" : 27017,
"version" : "5.0.5",
"gitVersion" : "d65fd89df3fc039b5c55933c0f71d647a54510ae"
},
"serverParameters" : {
"internalQueryFacetBufferSizeBytes" : 104857600,
"internalQueryFacetMaxOutputDocSizeBytes" : 104857600,
"internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600,
"internalDocumentSourceGroupMaxMemoryBytes" : 104857600,
"internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600,
"internalQueryProhibitBlockingMergeOnMongoS" : 0,
"internalQueryMaxAddToSetBytes" : 104857600,
"internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600
},
"ok" : 1
}