目录
介绍
1. MongoDB是一款非关系型数据库(NoSQL),是一个基于文档的数据库,数据以类似JSON的BSON(Binary JSON 二进制形式的JSON)格式进行存储。但我们在操作数据时是以JSON格式进行交互的,因为内部存在JSON和BSON的转换。
2. MongoDB可以存储复杂的数据结构,包括嵌套JSON对象和数组等。
3. MongoDB主要以磁盘进行存储,但存在磁盘映射加快数据的访问,所以适合存储大量的数据。
4. 由于依赖磁盘存储,所以性能相对Redis来说稍低,但是通过内存映射和缓存机制仍然能处理高并发和大量数据的读写请求。
5. MongoDB支持像MYSQL那样的复杂查询,并且支持事务(ACID),索引等。
看看存储结构
如上是同一个集合/表中的所有文档(JSON)数据,可以看到存储的方式是很灵活,第三个文档数据多了个gender字段,第四个文档数据的结构跟前三个完全不同,这是因为MongoDB是不用事先定义好集合/表结构的。
但是这样的存储一般是不推荐的,一般把相同/相似的数据结构存放到同一集合中。
通过如上的存储方式,我们知道存储的数据就是一堆JSON格式的数据。
至于JSON这样的存储方式,实际上对比关系型数据库(如MYSQL)更有灵活性:例如我们要存储用户信息,用户信息对象中包含“兴趣”字段,兴趣字段存储的数据结构为“数组”,那么我们为了保证满足第一范式,一般会创建一个“用户兴趣表”,此表与用户ID进行关联。
那么如果在MongoDB中,我们则可以直接使用字段值类型为数组的形式进行定义赋值即可。
安装MongoDB
如下在CentOS8中使用Docker进行MongoDB的安装。
1. 拉取MongoDB镜像
docker pull mongo:latest
2. 创建本地文件夹映射数据卷
创建文件夹:config (配置) , data (数据) , logs(日志)
创建文件:mongod.conf(启动配置文件)
mkdir -p 你的目录(如/mongo,自定义)/config
mkdir -p 你的目录/data
mkdir -p 你的目录/logs
touch 你的主目录/config/mongod.conf
chmod 777 你的目录
3. 编辑配置文件(mongod.conf)
用来定义MongoDB的启动信息。
# 数据库存储路径
dbpath=你的目录/data
# 日志文件路径
logpath=你的目录/logs/mongod.log
# 监听的端口
port=27017
# 允许所有的 IP 地址连接
bind_ip=0.0.0.0
# 启用日志记录
journal=true
# 是否后台运行
fork=true
# 启用身份验证
#auth=true
4. 启动MongoDB容器
docker run -dit --name mongo \
-p 27017:27017 \
-v 你的目录/config/mongod.conf:/etc/mongod.conf \
-v 你的目录/data:/data/db \
-v 你的目录/logs:/var/log/mongodb \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=123456 \
--restart=always \
mongo
5. 测试链接,使用
# 进入MongoDB的命令行(Mongo shell)
docker exec -it mongo /bin/mongosh
# 切换到admin数据库进行身份验证
use admin
db.auth("admin", "123456")
# 查看所有数据库
show dbs
查看数据库状态-常用命令表
用户管理
创建管理员用户
db.createUser(
{
user:"user_1",
pwd:"123456",
roles:[{role:"root"}]
}
);
命令字段解释:
user:用户名
pwd:密码
role:角色(不同角色有不同权限)
创建特定数据库管理员
如果我们想要创建某个数据库的管理员,让此用户仅仅能看到指定的数据库,而不能看到其他数据库,可以这样:
db.createUser(
{
user:"user1",
pwd:"123456",
roles:[{role:"dbOwner",db:"my_db"}]
}
);
可以看到上述命令:
role:声明成了dbOwner,代表属于指定数据库。
db字段:代表属于哪个数据库
整体代表:user1这个用户声明为了my_db数据库的管理员,当user1用户登录后,仅仅能够看到my_db这个数据库。
删除用户
db.dropUser({'user1'})
查看所有用户
show users
数据库创建和删除
我们可以使用use命令来创建数据库,当use 的数据库不存在时,则是新增。
例如:我们要创建数据库my_db,可以使用:use my_db
值得注意的是:当我们使用use去创建一个新数据库时,然后使用命令“show dbs”查看数据库,不会直接看到新创建的数据库,因为MongoDB中的数据库创建是惰性创建的,只有数据库中存在至少一个集合/表才会真正创建/显示。
创建新数据库:newDB,使用show dbs查看不直接显示newDB数据库
然后在newDB下新建一个集合tb1
再次show dbs查看,可以看到newDB正常显示。
删除数据库
db.dropDatabase("数据库名")
集合的创建和删除
查看数据库中的所有集合
show tables
or
show collections
创建
db.createCollection("集合名称")
删除
db.集合名.drop()
文档操作(CRUD)
新增操作
# 插入单条数据
db.my_c.insertOne({name: "张三", age: 18})
# 批量插入数据
db.my_c.insertMany([{name: "Tom1", age:90}, {name: "Jerry", age: 100}...])
通过js脚本批量插入数据
JS脚本的执行:
命令:load("JS脚本文件路径")
查询操作
查询所有
db.集合名.find()
直接使用find()不带参数,代表查询所有,但是输出默认为20条,如果想要往下查询更多数据,输入命令”it”,翻页操作。
简单条件查询
db.my_c.find({age: 18})
db.my_c.find({age: 18, name: "张三"})
如上为等值匹配查询,{字段:字段值}
复杂条件查询
我们可以使用范围查询,如大于,小于,不等于...
查询年龄大于50的用户:
可以看到我们是以$gt这样的特殊字符来表示大于,其他的小于,不等于也类似:
以及,逻辑对照表:
排序和分页
查询所有并按照年龄进行降序:
db.my_c.find().sort({age: -1})
1为升序排序,-1为降序排序。
分页查询
MongoDB中的分页是通过skip() 和 limit() 配合实现的。
skip():代表跳过多少条
limit():显示输出多少条
例如每页显示10条,输出第三页:
db.my_c.find().skip(20).limit(10);
如上limit()就是控制显示的条数
而skip的参数计算可以为:页数-1 *显示条数
模糊查询
查询名称中包含“T”的文档:
db.my_c.find({name: {$regex:"T"}})
或者
db.my_c.find({name: /T/})
更新文档
例如,将Jerry的年龄+1 :
db.my_c.update({name: "Jerry"}, {$inc:{age: 1}})
其中使用到了更新操作符“$inc”,更多更新操作符:
在上面的update更新中,默认仅更新一条就执行结束了,如果想要更新多条(匹配条件的所有数据) ,则需要配置update中的第三个对象参数{multi: true}:
# 更新匹配到的所有数据
db.my_c.update({name: "Jerry"}, {$inc:{age: 1}}, {"multi": true})
删除文档
# 删除单个
db.my_c.deleteOne({age: 18})
# 删除所有匹配项
db.my_c.deleteMany({age: 18})
其中的deleteOne()仅删除第一个匹配的数据。
MongoDB可视化操作数据的软件
官方软件:MongoDBCompass
下载地址:MongoDB Compass Download (GUI) | MongoDB
Navcat也可以连接MongoDB
但是Navcat可提供的操作相对MongoCompass更局限一些。
聚合操作
什么是聚合操作?
聚合操作是处理数据记录并返回计算结果的操作,如统计平均值,求和,分组等操作。
单一聚合
提供简单的聚合操作,如单求平均值,求和等,都是在单个集合中进行操作。
如:统计个数,去重操作
可以看到.count()显示方法已经过时。
聚合管道
对于更复杂的聚合操作,一般使用聚合管道实现,聚合管道非常的灵活,可以任意组合聚合操作,将上一个聚合操作的输出数据,作为下一个聚合操作的输入数据。
聚合管道语法:db.集合名.aggregate(pipeline, {options})
pipeline:一组聚合操作,[{ 聚合操作1 }, { 聚合操作2 }...]
options:可选参数,聚合操作的参数。包括查询计划,是否使用临时文件,游标等。
聚合管道操作表
例如:我们想要通过聚合管道过滤出年龄大于10的用户姓名
# 我们可以通过$match 和 $project配合使用,达到效果
db.my_c.aggregate([{$match: {age:{$gt:10}}}, {$project: {name: 1}}])
如上,我们先通过$match过滤出年龄大于10的所有用户信息,然后将数据传递到$project做投影操作,仅取出名称。
从如上操作可得知,我们可以利用各种聚合操作在[{}, {}...]中拼接,最终达到我们的聚合效果。
值得注意的是:一个重要的聚合操作$lookup
$lookup
我们可以通过lookup进行多表联合查询。
案例:例如我们现在有两个集合:用户“customer” 和订单 “order” ,两者通过用户ID“customerCode”进行关联。
我们要查询用户用户的所有订单信息:
更多聚合操作或示例:聚合管道 - MongoDB手册
索引操作
MongoDB和MYSQL一样都存在索引,且两者的索引结构实现都是B+树,目的就是为了提高查询效率。
创建索引
语法:db.my_c.createIndex(keys, options)
keys:创建索引的字段列表
options:可选参数
可选参数表:
例如:我们要给用户信息的“名称”创建索引:
# 为name字段创建单独的索引
db.my_c.createIndex({name: 1})
# 创建name 和 age字段的复合索引
db.my_c.createIndex({name: 1, age: 1})
查看索引
db.集合名.getIndexes()
删除索引
# 删除集合中指定索引
db.集合名.dropIndex("索引名")
# 删除集合中所有索引
db.集合名.dropIndexes()
检查索引的使用
我们可以使用explain工具查询MongoDB的执行计划,查看查询是否使用了索引。
没有索引的情况:执行“db.my_c.find({age: {$gt:18}}).explain()”
可以看到为“COLLSCAN”,意思为全表扫描,时间复杂度为O(n)效率必然差些。
我们给age字段添加上索引,再次查询:
发现这一次的stage为“IXSCAN”,索引扫描。