基本概念
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库
NoSQL
非关系型数据库的一系列统称,常见的比如redis,mongodb,neo4j;mongodb 以文档的形式存储数据,数据表现形式和JSON类似,MongoDB里面叫BSON,BSON会支持一些JSON不支持的数据格式,如Date,BinData
主键,MongoDB自动将_id字段设置为主键
应用场景
如果项目的数据模式是固定的,而且不需要频繁变更,推荐使用 MySQL,因此项目维护容易,而且确保了数据的完整性和可靠性。
另一方面,如果项目中的数据持续增加,而且数据模式不固定,MongoDB 是最合适的选择。由于它属于非关系数据库,数据可以自由使用,不需要定义统一的数据结构,所以对数据进行更新和查询也很方便。MongoDB 通常用于需要对内容进行管理、处理物联网相关业务、进行实时分析等功能的项目中。
技术解析
系统架构
主从模式(Master-Slave)
热备,读写分离,oplog同步数据;数据一致性问题;主节点宕机需要手动把slave节点指定为master节点,无法自愈(不推荐)
副本集模式(Replica Set)
和redis的哨兵模式类似
"脑裂"问题
分片模式(sharding)
可以简单地理解为是副本集模式的集群模式,并且加了一层代理层和配置层
代理层:访问数据时路由到具体的副本集
配置层:帮忙做负载均衡的
事务
4.0开始支持事务(副本集模式)
4.2及以上支持(分片模式的事务)
建议做合理的数据表格设计,尽量做单文档操作
数据存储引擎
WiredTiger:数据存放在磁盘上
In-Memory:数据存放在内存中(mongo进程杀掉之后就没数据量,需要通过oplog日志来恢复)
一般来讲主节点一定要WiredTiger,从节点可以用In-Memory提高效率
索引
b树(索引+数据)
非关系型数据库mongodb 设计表格时区别于关系型数据库的设计;关系型数据设计需要遵循3范式,多表查询遍历多,需要读取更多的索引;非关系型数据库 比较适合单一查询,不涉及遍历操作
基本语法
常用指令 xshell 登录172.26.1.247
cd /home
sh enter_container.sh mongo
mongosh
enter_container.sh
#!/bin/bash
echo "container name: $1"
containerId=$(docker ps |grep "$1" | awk '{print $1}')
echo "get containerId: $containerId"
docker exec -it "$containerId" /bin/sh
#查看已有数据库
show dbs
#创建使用数据库
use ccp_monitor
#mongo中不需要事先建立表格,插入数据时自动生成
db.userinfo.insert({"name":"lsj","age":18})
#但需要自己创建索引,注意要设置background=true 不然会锁表
#创建普通索引
db.userinfo.createIndex({"name":1},{background:true})
#创建唯一索引
db.userinfo.createIndex({"userId":1},{background:true,unique:true})
#创建联合索引
db.userinfo.createIndex({"name":1,"sex":1},{background:true})
增删改查
添加记录
#添加记录
db.tablename.insert({json数据})
#example
db.userinfo.insert({"name":"lsj","age":18})
修改记录
# 修改记录
db.tablename.update({条件},{操作})
#example
db.userinfo.update({"name":"cd","sex":1},{$set:{"age":99}})
#插入或更新
db.userinfo.update({"name":"cjf","sex":1},{$set:{"age":99}},{"upsert":true})
查询记录
# 查询记录
db.tablename.find({条件},{返回字段(可选)})
#example
#查询user表的所有数据
db.userinfo.find();
#多个检索条件封装成json
db.userinfo.find({"name":'cd',"sex":1})
db.userinfo.find({"name":'cd',"sex":1},{"name":1})
删除记录
#删除记录
db.tablename.remove({条件(可选)})
#example
db.userinfo.remove({"name":'lsj'})
内嵌函数
db.userinfo.find({"$where":function(){return this.age>40;}})
db.userinfo.find({"$where":function(){return this.age>40&&this.sex==1;}})
查询内嵌文档中满足条件的记录
#查询child年龄小于等于5的记录(全部)
db.userinfo.find({"child.age":{$lte:5}})
[
{
_id: ObjectId("632bd90a29dd2c5a24dbf033"),
name: 'cjf',
sex: 1,
age: 99,
child: [ { name: 'a', age: 10 }, { name: 'b', age: 5 } ]
}
]
#查询child年龄小于等于5的记录(符合条件的child)
db.userinfo.find({"child.age":{$lte:5}},{"child.$":1})
[
{
_id: ObjectId("632bd90a29dd2c5a24dbf033"),
child: [ { name: 'b', age: 5 } ]
}
]
原子指令操作
应用场景,需要修改某个实体下的某个属性;这个属性可能是一个基本数据类型,也可能是内嵌文档
为了解决这类并发问题,mongo提供了一系列操作符来简化操作
set:用来指定一个键并更新键值,若键不存在并创建;对于内嵌文档在使用unset:删除键 pull:从数组field内删除一个等于value值 pop:删除数组尾部元素(参数1) 删除数组头部元素(参数-1)
表连接查询(基本不用)
db.gameapp.aggregate([
{
$match: {name: 'qysg10001'}
},{
$lookup: {
from: 'hosts',
localField: 'host_id',
foreignField: '_id',
as: 'host_info'
}
},{
$unwind: {
path: '$host_info',
preserveNullAndEmptyArrays: true,
}
},{
$project: {
_id: 0,
'host_info.host': 1,
'host_info.private_ip': 1,
'host_info.status': 1,
}
}
])
图形化界面工具
robo 3t
MongoDB Compass(官方提供的,建议使用)
两个软件都支持页面编辑和指令编辑,都有代码提示
主要演示一下robo 3t的使用,具体看演示
配置连接信息
查看数据
会自动生成一个查询模板
添加/编辑/删除数据 右键
语言集成
java
springboot集成了mongodb驱动,客户端,只需要在pom文件中导入jar包,配置连接信息,利用spring的自动装配原理,管理连接
python
pymongo
from pymongo import MongoClient
if __name__ == '__main__':
client = MongoClient(host='172.26.1.247', port=27017)
userinfo = client['ccp_monitor']['userinfo']
result = userinfo.find_one({"name": 'lsj'})
print(result)
更多使用方法:API Documentation — PyMongo 4.2.0 documentation
经验分享
1.建索引
本身mongo就是基于b树做索引的,检索的时候索引和数据都会读到,没有索引会导致全表扫描,响应慢
2.创建索引,注意要设置background=true 不然会锁表(生产环境很危险!)
3.原子操作尽量使用数据库自带的
4.尽量使用单表操作,避免外联查询
5.避免使用数据库的唯一id做检索条件
知识拓展 GeoJson
如果不想用postgis,mongodb的GeoJson是最佳选择