MongoDB基础操作

一、什么是MongoDB

MongoDB 是一个开源、高性能、无模式的、基于分布式文件存储的文档型数据库,当初的设计就是用于简化开发和方便扩展,是 NoSQL 数据库产品中的一种。是最像关系型数据库(MySQL)的非关系型数据库。

它支持的数据结构非常松散,是一种类似于JSON的格式叫BSON(Binary JSON),所以它既可以存储比较复杂的数据类型,又相当的灵活。

二、MongoDB 与关系型数据库对比

webp

SQL 术语/概念 MongoDB 术语/概念 解释说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 不支持 表连接,MongoDB 不支持
不支持 嵌入文档 MongoDB 通过嵌入式文档来替代多表连接
primary key primary key 主键,MongoDB 自动将_id 字段设置为主键

三、数据类型

数据类型 描述 举例
字符串 utf8字符串都可以表示为字符串类型的数据
对象id 对象id是文档的12字节的唯一ID
布尔值 真或者假:true或者false
数组 值的集合或者列表都可以表示成数组
整数 (Int32 Int64 你们就知道有个Int就行了,一般我们用Int32)
null 表示空值或者未定义的对象
undefined 文档中也可以使用未定义类型

四、部署MongoDB

1、下载二进制包

下载地址

image-20240424165506053

2、下载安装包并解压

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.6.tgz
tar xzvf mongodb-linux-x86_64-rhel70-4.4.6.tgz -C /usr/local
cd /usr/local/
ln -s /usr/local/mongodb-linux-x86_64-rhel70-4.4.6 /usr/local/mongodb

3、创建用于存放数据和日志的目录,并修改权限

# 创建存放数据的目录
mkdir -p /usr/local/mongodb/data/db
# 创建存放日志的目录
mkdir -p /usr/local/mongodb/logs
# 创建日志记录文件
touch /usr/local/mongodb/logs/mongodb.log

4、启动MongoDB

4.1前台启动

MongoDB的默认启动方式为前台启动

cd /usr/local/mongodb/

bin/mongod \
--dbpath /usr/local/mongodb/data/db/ \
--logpath /usr/local/mongodb/logs/mongodb.log \
--logappend \
--port 27017 \
--bind_ip 0.0.0.0

参数解释:

 --dbpath:指定数据文件存放目录
 --logpath:指定日志文件,注意是指定文件不是目录
 --logappend:使用追加的方式记录日志
 --port:指定端口,默认为 27017
 --bind_ip:绑定服务 IP,若绑定 127.0.0.1,则只能本机访问,默认为本机地址

4.2后台启动

后台启动在命令中添加--fork即可

cd /usr/local/mongodb/

bin/mongod \
--dbpath /usr/local/mongodb/data/db/ \
--logpath /usr/local/mongodb/logs/mongodb.log \
--logappend \
--port 27017 \
--bind_ip 0.0.0.0 \
--fork

4.3、配置文件启动服务

bin目录下增加一个mongodb.conf配置文件

vim /usr/local/mongodb/bin/mongodb.conf
# 数据文件存放目录
dbpath = /usr/local/mongodb/data/db
# 日志文件存放目录
logpath = /usr/local/mongodb/logs/mongodb.log
# 以追加的方式记录日志
logappend = true
# 端口默认为 27017
port = 27017
# 对访问 IP 地址不做限制,默认为本机地址
bind_ip = 0.0.0.0
# 以守护进程的方式启用,即在后台运行
fork = true

image-20240424171746978

启动命令:

bin/mongod -f /usr/local/mongodb/bin/mongodb.conf

image-20240424172044021

4.4、配置systemd服务

vim /usr/lib/systemd/system/mongodb.service

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target 
[Service] 
Type=forking 
ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/bin/mongodb.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /usr/local/mongodb/bin/mongodb.conf
PrivateTmp=true 
[Install] 
WantedBy=multi-user.target

chmod 754 /usr/lib/systemd/system/mongodb.service

4.5、systemctl启动MongoDB

systemctl start mongodb

5、客户端配置

添加环境变量

echo "export PATH=/usr/local/mongodb/bin/:$PATH" >> /etc/profile
source /etc/profile
mongo

6、关闭MongoDB

6.1、前台启动

Ctrl + c

6.2、后台启动

# 命令启动方式的关闭
bin/mongod --dbpath /usr/local/mongodb/data/db/ --logpath /usr/local/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0 --fork --shutdown
# 配置文件启动方式的关闭
bin/mongod -f /usr/local/mongodb/bin/mongodb.conf --shutdown

6.3、kill命令关闭

不推荐使用

# 查看 mongodb 运行的进程信息
ps -ef | grep mongodb
# kill -9 强制关闭
kill -9 pid

6.4、MongoDB函数关闭

# 连接 mongodb
mongo
# 切换 admin 数据库
use admin
# 执行以下函数(2选1)即可关闭服务
db.shutdownServer()
db.runCommand("shutdown")

五、MongoDB基本操作及增删改查

1、基本操作

1.1、登录数据库

mongo

1.2、查看数据库

show databases
show dbs

image-20240424183039764

1.3、查看当前正在使用的数据库

db

image-20240425115609645

1.4、选择/创建数据库

use admin

image-20240425114338328

如果切换到一个没有的数据库,那么会隐式创建这个数据库。(后期当该数据库有数据时,系统自动创建)

use admin1

image-20240425114612080

1.5、查看集合

show collections

image-20240425114752959

1.6、创建集合

db.createCollection('集合名')

image-20240425115030221

1.7、删除集合

db.集合名.drop()

image-20240425115744209

1.8、删除数据库

通过use语法选择数据
通过db.dropDataBase()删除数据库

> use admin1
switched to db admin1
> show collections
c2
> db.dropDatabase()
{ "dropped" : "admin1", "ok" : 1 }
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

image-20240425120604758

2、增删改查

2.1、插入文档

如果集合存在,那么直接插入数据。

如果集合不存在,那么会隐式创建。

db.集合名.insert(JSON数据)
  • 在test1数据库的c1集合中插入文档,(姓名:张三,年龄:18)
> use test1
switched to db test1
> show collections
> db.createCollection('c1')
{ "ok" : 1 }
> db.c1.insert({name:"张三",age:18})
WriteResult({ "nInserted" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }

image-20240425125211753

  • 数据库和集合不存在都隐式创建
  • 对象的键统一不加引号(方便看),但是查看集合数据时系统会自动加
  • mongodb会给每条数据增加一个全球唯一的_id
2.1.1、一次性插入多条数据
  • 数组中一个个写入json数据
> db.c1.insert([{name:"李四",age:20},{name:"王五",age:21},{name:"赵六",age:22}])
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 3,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六", "age" : 22 }

image-20240425125249398

  • 写for循环插入数据
> for (var i=1;i<=10;i++) {db.c1.insert({name:"a"+i , age: i}) }
WriteResult({ "nInserted" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125400607

2.2、查询文档

db.集合名.find(条件[,查询的列])
条件 写法
查询所有的数据 {}或者不写
查询age=6的数据
既要age=6又要性别=男
查询的列(可选参数) 写法
查询全部列(字段) 不写
只显示age列(字段)
除了age列(字段)都显示

其他语法

db.集合名.find({
            键:{运算符:值}
            })
运算符 作用
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in in
$nin not in
  • 查看所有数据
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125449664

  • 只看name列
> db.c1.find({},{name:1})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三" }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四" }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五" }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六" }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1" }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2" }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3" }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4" }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5" }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6" }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7" }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8" }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9" }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10" }

image-20240425125526995

  • 查看除了name列
> db.c1.find({},{name:0})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "age" : 10 }

image-20240425125554132

  • 查询age大于6的数据
> db.c1.find({age:{$gt:6}})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125634325

  • 查询年龄为7岁、10岁、18岁的数据
> db.c1.find({age:{$in:[7,10,18]}})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "张三", "age" : 18 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425142853007

2.2.1、查询集合内所有的记录数
db.集合名.count()

image-20240425205417337

2.3、修改文档

db.集合名.update(
  <filter>,          // 查询条件(筛选待更新的文档)
  <update>,          // 更新操作定义(如何修改文档)
  {
    upsert: <boolean>,  // 可选,如果无匹配文档则插入,默认为 false
    multi: <boolean>,   // 可选,是否更新所有匹配的文档,默认为 false(仅更新第一条)
    collation: <object>, // 可选,指定比较选项(如大小写敏感等)
    arrayFilters: <array>, // 可选,用于处理嵌套数组中的条件匹配
    hint: <string|document>, // 可选,提供索引来指导查询
    writeConcern: <document>, // 可选,指定写关注级别
    let: <object> // 可选,用于与聚合管道更新相关的变量定义
  }
)
  • {name:"张三"}修改为{name:"zhangsan"}
> db.c1.update({name:"张三"},{$set:{name:"zhangsan"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "zhangsan", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "赵六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425184009386

  • {name:"李四"}的年龄加/减5

年龄加5

db.c1.update({name:"李四"},{$inc:{age:5}})

image-20240425184419154

年龄减5

db.c1.update({name:"李四"},{$inc:{age:-5}})

image-20240425184616300

2.4、删除文档

db.集合名.remove(条件[,是否删除一条])
  • 删除一条数据

    • db.c1.remove({},true)
      

      默认删除的第一条数据

      image-20240425204653851

    • db.c1.remove({name:"李四"})
      

      删除指定数据

      image-20240425204856853

六、MongoDB支持存储的数据类型

1、数字

  • shell默认使用64位浮点型数值
db.b1.insert({x:3.1415926})
db.b1.insert({x:3})

image-20240425213512686

  • 整型值,可以用NumberInt或者NumberLong表示
db.b1.insert({x:NumberInt(10)})
db.b1.insert({x:NumberLong(12)})

image-20240425213843340

2、字符串

db.b1.insert({x:"hello MongoDB!"})

image-20240425214353152

3、正则表达式

查询所有keyx,valuehello开头的文档且不区分大小写

db.b1.find({x:/^(hello).(.[a-zA-Z0-9])+/i})

image-20240425214936289

4、数组

数组中的数据类型可以是多种多样的

db.b1.insert({x:[1,2,3,4,new Date()]})

image-20240425215940415

5、日期

db.b1.insert({x:new Date()})

image-20240425220308105

6、内嵌文档

一个文档也可以作为另一个文档的value

db.b1.insert({name:"三国演义",author:{name:"罗贯中",age:70}})

image-20240425221008151

七、MongoDB中的索引

1、查看索引

默认情况下,集合中的_id字段就是索引,我们可以通过getIndexes()方法来查看一个集合中的索引:

db.b1.getIndexes()

image-20240425222309926

  1. v: 表示索引版本。在这个例子中,值为 2,表示这是一个版本 2 的索引。索引版本通常由 MongoDB 内部管理,用户通常不需要直接关心。
  2. key: 描述了索引的键(即排序依据)。键是一个对象,键名为字段名,键值为排序方向。在给出的例子中,{ "_id" : 1 } 表示索引基于字段 _id,且按升序(1)排序。在 MongoDB 中,每个集合都默认有一个名为 _id 的主键索引,它是唯一的,并且总是按升序排列。
  3. name: 指定索引的名称。这里为 "name" : "_id_",表示这是一个针对 _id 字段的索引,其名称默认为 _id_。在 MongoDB 中,主键索引的名称通常是固定的,即 _id_

2、需要索引的查询场景

2.1、创建有10000个文档的集合

for (var i=1;i<=10000;i++) {db.q1.insert({name:"test"+i , age: i})}
db.q1.count()

image-20240426082844602

2.2、查询age200的文档

db.q1.find({age:200})

image-20240425230647795

这种查询默认情况下会做全表扫描,可以用explain()来查看一下查询计划

db.q1.find({age:200}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 200
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 200
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 2,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 10000,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 200
                                }
                        },
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 10002,
                        "advanced" : 1,
                        "needTime" : 10000,
                        "needYield" : 0,
                        "saveState" : 10,
                        "restoreState" : 10,
                        "isEOF" : 1,
                        "direction" : "forward",
                        "docsExamined" : 10000
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}

queryPlanner 部分

  • plannerVersion: 表示查询优化器的版本。
  • namespace: 查询涉及的集合名,即 test3.q1
  • indexFilterSet: 若为 true,表示查询使用了索引过滤器;此处为 false,说明没有使用。
  • parsedQuery: 显示解析后的查询条件,即查找 age 字段等于 200 的文档。
  • winningPlan: 描述被选择的执行计划。在这个案例中,执行计划的 stage"COLLSCAN",意味着进行了全集合扫描(Collection Scan)。这意味着为了找到匹配的文档,MongoDB 需要遍历整个 q1 集合,对每个文档应用 filter 中指定的条件(age: { $eq: 200 })。
  • rejectedPlans: 空数组,表示没有其他备选执行计划被否决。如果有多个可行计划,MongoDB 会选择成本最低的一个作为 winningPlan,其余的则记录在此处。

executionStats 部分

这部分提供了实际执行查询时的统计信息:

  • executionSuccess: 指示查询是否成功完成,true 表示成功。
  • nReturned: 返回的文档数量,这里是 1,说明找到了一个年龄为 200 的文档。
  • executionTimeMillis: 执行查询所花费的时间(毫秒),本例中为 2 毫秒。
  • totalKeysExamined: 查看的索引键数量。由于未使用索引,此处为 0
  • totalDocsExamined: 查看的文档数量,即全集合扫描过程中检查过的文档总数,这里为 10000,表明集合中有 10000 个文档被逐一检查以找出符合 age: 200 的文档。
  • executionStages: 提供了更多关于执行阶段的细节,与 winningPlan 相对应。这里再次确认了进行了全集合扫描(COLLSCAN),并且实际查看了 10000 个文档 (docsExamined) 才找到 1 个匹配的文档 (nReturned).

serverInfo 部分

  • 提供了运行 MongoDB 服务器的主机名、端口、版本号以及 Git 版本信息。

ok

  • 值为 1,表示命令执行成功。

2.3、添加limit查询文档

db.q1.find({age:10}).limit(20)

db.q1.find({age:10}).limit(20).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 10
                        }
                },
                "winningPlan" : {
                        "stage" : "LIMIT",
                        "limitAmount" : 20,
                        "inputStage" : {
                                "stage" : "COLLSCAN",
                                "filter" : {
                                        "age" : {
                                                "$eq" : 10
                                        }
                                },
                                "direction" : "forward"
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 4,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 10000,
                "executionStages" : {
                        "stage" : "LIMIT",
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 1,
                        "works" : 10002,
                        "advanced" : 1,
                        "needTime" : 10000,
                        "needYield" : 0,
                        "saveState" : 10,
                        "restoreState" : 10,
                        "isEOF" : 1,
                        "limitAmount" : 20,
                        "inputStage" : {
                                "stage" : "COLLSCAN",
                                "filter" : {
                                        "age" : {
                                                "$eq" : 10
                                        }
                                },
                                "nReturned" : 1,
                                "executionTimeMillisEstimate" : 1,
                                "works" : 10002,
                                "advanced" : 1,
                                "needTime" : 10000,
                                "needYield" : 0,
                                "saveState" : 10,
                                "restoreState" : 10,
                                "isEOF" : 1,
                                "direction" : "forward",
                                "docsExamined" : 10000
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}

可以明显感受到加了limit后查询速度变快了很多

但是如果我们查询age9999的文档那么还是得全表扫描一遍

此时我们就可以给该字段加上索引

2.4、创建索引

db.collection.createIndex(keys, options)

参数:

  • keys:

    • 包含字段和值对的文档,其中字段是索引键,描述该字段的索引类型
    • 对于字段的上升索引,请指定为1,对于降序指定为-1
  • options:

    • 可选,包含一组控制索引创建的选项的文档
    选项 类型 描述
    background 布尔 是否在后台执行创建索引的过程,不阻塞对集合的操作false【默认】
    unique 布尔 是否创建具有唯一性的索引 false【默认】
    name 字符串 自定义索引名称,如果不指定,mongodb将通过 下划线 连接 索引字段的名称和排序规则 生成一个索引名称。一旦创建不能修改,只能删除再重新创建
    partialFilterExpression Document 仅为集合中符合条件的文档建立索引,降低创建和维护成本
    sparse 布尔 仅为集合中具有指定字段的文档建立索引 false 【默认】
    expireAfterSeconds integer单位 秒 用于 TTL 索引中 控制 文档保存在集合中的时间
    storageEngine Document 指定存储引擎配置
db.q1.ensureIndex({age:1})

查看查询计划

db.q1.find({age:200}).explain("executionStats")
> db.q1.find({age:200}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 200
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "age" : 1
                                },
                                "indexName" : "age_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[200.0, 200.0]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 1,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 2,
                        "advanced" : 1,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "docsExamined" : 1,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 1,
                                "executionTimeMillisEstimate" : 0,
                                "works" : 2,
                                "advanced" : 1,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 0,
                                "restoreState" : 0,
                                "isEOF" : 1,
                                "keyPattern" : {
                                        "age" : 1
                                },
                                "indexName" : "age_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[200.0, 200.0]"
                                        ]
                                },
                                "keysExamined" : 1,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}
  • executionTimeMillis:执行耗时 1 毫秒。

  • totalKeysExaminedtotalDocsExamined:分别检查了 1 个索引键和 1 个文档。由于使用了覆盖索引(即索引包含了查询所需的所有字段),这里的两个值相等,意味着无需额外查询文档。

查看索引

> db.q1.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "age" : 1
                },
                "name" : "age_1"
        }
]

image-20240426093010417

2.5、自定义索引名字

db.q1.ensureIndex({name:1},{name:"MyNameIndex"})

image-20240426102603193

3、查看索引的大小

默认单位是字节

db.q1.totalIndexSize()

image-20240426102044812

4、删除索引

4.1、按名称删除索引

db.q1.dropIndex("MyNameIndex")

image-20240426102841487

4.2、删除所有的索引

db.q1.dropIndexes()

image-20240426103015481

5、优缺点

5.1、优点:

  • 提高查询性能:索引能够大大加快数据查询速度,特别是对于含有复杂查询条件、排序、分组或聚合操作的查询。
  • 支持高效排序:当查询需要对特定字段进行排序时,如果该字段有索引,MongoDB可以直接利用索引来完成排序,避免了大量数据的内部排序操作,显著提升性能。
  • 覆盖查询:如果一个索引包含了查询所需的全部字段,称为“覆盖索引”。在这种情况下,MongoDB可以直接从索引中获取所有数据,而无需访问实际文档,从而减少磁盘I/O操作,提高查询效率。
  • 唯一性约束:创建唯一索引可以确保指定字段的值在整个集合中唯一,防止插入重复数据,确保数据完整性。

5.2、缺点:

  • 占用存储空间:索引需要额外的存储空间来保存索引数据结构。随着数据量的增长和索引数量的增加,存储开销会逐渐增大。需要根据实际业务需求权衡查询性能与存储成本。
  • 写操作性能影响:插入、更新和删除文档时,不仅要修改原数据,还要同步更新相关索引。对于写密集型应用,大量的索引可能导致写操作性能下降,尤其是当索引较多或索引字段频繁变动时。
  • 索引维护成本:随着数据的变化,索引需要不断维护和更新。对于大型数据集,索引重建可能需要消耗较长时间和系统资源。此外,随着业务发展,可能需要定期评估和调整索引策略,以适应新的查询模式。
posted @ 2024-04-26 10:46  misakivv  阅读(625)  评论(0编辑  收藏  举报