首页 > 技术文章 > nosql之MongoDB

LZXX 2022-02-17 17:57 原文

大数据时代的3v
海量数据 volume:sql 上千万慢 mysql 34千万慢(都过亿了 就凉凉)而 orecle 集群太贵

多样数据variety:多种多样的数据:建立一个表的时候 可以给这个表里面插任何数据, 如json 建立一个表的时候 可以给这个表里面插任何数据, 如json 在关系型数据库不行

实时数据-velocity:读写数据-并发高 要实时

互联网需求的3高
高并发:关系型数据访问的数据是直接硬盘读取 并发高造成io高会报错 数据库连接数量会达到瓶颈(一般遇到sql拒绝就是访问数量超出or访问时间超长)
    原因基本就是:就是处理请求太慢了,数据直接取操作硬盘,所以就可以用内存-redis mongodb(根据业务选择中间件) 解决高并发
高可扩:适用中间件搭建集群简单,不行就扩展,放在mysql不好实现
高性能:合理利用起来就是高性能了

这里可以看出nosql的强大之处,但是具体数据库选择是RDBMS还是NoSql 是看项目的

 

MongoDB

1.是分布式的-(像redis,kafka),数据存储于硬盘,但是经常读取的数据会弄到内存中去 内存数据映射-提高查询效率

2.分布式优点

  可靠性(容错):一台服务器崩溃不影响到其他服务器,如mysql数据库一挂,整个网站都GG

  可扩展:根据需求增加更多机器,原先只能加硬件

  资源共享:如用户数据,订单数据,财务数据,各个系统之间共享

  灵活性:分布式下容易安装,实施和调试新的服务

  更快的速度:分布式计算系统可以有多台计算机的计算能力,中间件有更快的速度就是利用刷盘机制

  开放:本地和远程都可以访问该服务

  更高的性能和更好的性价比

3.分布式缺点

故障排除:出现问题排除和诊断更麻烦

网络:传输问题,高负载,信息丢失。 因为是各个进程间通信 网络波动都影响-nosql,丢数据比例比RDBMS更大

安全:开放系统的特性让分布式计算系统安全和共享更高

mongodb刷盘机制(高效的原理)

1.mysql数据存储是直接存到Data file(dsik硬盘)里面的 所以小数据没啥问题,大量数据就响应慢,但数据不会丢失

2.而mongodb 存到ram缓冲区之后直接返回给客户端(说我保存成功了,响应快) 然后每100ms(可配置时间)把缓冲区的数据存到日志文件硬盘里面,最后os flush/60s(可配置) 然后存到硬盘

通俗解释,mysql发消息直接到数据库,好处就是消息不会丢失,但是并发慢

    mongodb相当于中间加了一层redis,高并发好,但是因为多了一层所以数据丢失性也高

3.提高mongdb读的性能(数据预热),本身有一个机制经常查的数据会放到内存中 所以可以写一个作业定时查一下经常查的数据

 

 

 

 

 

 

 

 

 

 

 

 

 如何解决海量数据下的16MB文档限制?

  1.提前存储的时候把关联关系做好,就不需要在业务中合并

  2.联查-通关数据冗余, 文档里面存 (子文档1的PID,子文档2的PID)  查出来之后聚合在业务中    文档相当于sql的表

 

 

 

 

如何使用

docker如何下载安装 mongodb

  指令运行:docker run -itd --name mongo -p 27017:27017 mongo

mongodb可视化查询

1.navicat premium

2.网页可视化管理工具 

docker run -it --rm \
--name mongo-express \
-p 8081:8081 \
-e ME_CONFIG_OPTIONS_EDITORTHEME="ambiance" \
-e ME_CONFIG_MONGODB_SERVER="192.168.3.214" \
-e ME_CONFIG_MONGODB_PORT="27017" \
-e ME_CONFIG_BASICAUTH_USERNAME="admin" \
-e ME_CONFIG_BASICAUTH_PASSWORD="admin" \
mongo-express

运行成功后

http://自己的本地ip:8081
用户名密码都是admin
View Code

 

mongodb查询操作

1.Mongodb基本操作
查询数据库
show databases
切换数据库
use test
查询当前数据库下面的集合
show collections
创建集合
db.createCollection("集合名称")
删除集合
db.集合名称.drop()
删除数据库
db.dropDatabase() //首先要通过use切换到当前的数据库
View Code

2.Mongodb增删改查(CURD)

id 系统会自动加一个
时间戳+机器码 生成
增(insert)
查询数据库
show databases
切换数据库
use test
查询当前数据库下面的集合
show collections
创建集合
db.createCollection("集合名称")
删除集合
db.集合名称.drop()
删除数据库
db.dropDatabase() //首先要通过use切换到当前的数据库
123456789
10
11
12
查(find)
排序&分页
新增一条
db.userinfo.insert({name:"贾宝",age:25,gander:"",address:'贾府'})
新增多条
db.userinfo.insert([{name:"贾宝",age:25,gander:"",address:'贾府'}
,{name:"林黛玉",age:16,gander:"",address:'林 府'}])
可不可以快速插入10条数据
for(var i=1;i<=10;i++) {
 db.userinfo.insert({name:"clay"+i,age:i})
 } 
123456789
10
11
查询所有的数据
db.集合名称.find({})
查询top条数
db.集合名称.find({}).limit(条数)
条件查询
 db.userinfo.find({name:"clay1",age:1},
{name:1,_id:0})
View Code
3.排序&分页
db.c1.insert({_id:1,name:"a",sex:1,age:1})
db.c1.insert({_id:2,name:"a",sex:1,age:2})
db.c1.insert({_id:3,name:"b",sex:2,age:3})
db.c1.insert({_id:4,name:"c",sex:2,age:4})
db.c1.insert({_id:5,name:"d",sex:2,age:5})
db.c1.find()
正序
db.c1.find({}).sort({age:1})
降序
123456789
10
运算符 作用
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in in
$nin not in
运算符
改(update)
db.集合名.update(条件, 新数据)
 {修改器: {键:值}}
 db.c1.find({}).sort({age:-1})
分页查询 跳过两条查询两条
 db.c1.find({}).sort({age:1}).skip(2).limit(2) 
11
12
13
View Code
4.运算符
//年龄大于1
db.c1.find({age:{$gt:1}})
//年龄是 3,4,5的
db.c1.find({age:{$in:[3,4,5]}})
View Code

5.update

db.集合名.update(条件, 新数据)
{修改器: {键:值}} 

修改器  作用
$inc    递增
$rename 重命名列
$set   修改列值
$unset  删除列

准备数据
 db.c1.insert({name:"8888",age:1,addr:'address',f
lag:true})
 db.c1.update({name:"8888"}, {name:"99"})
 db.c1.update({name:"8888"}, 
 {
  $set:{name: "zs44"},
  $inc:{age:10},
  $rename:{addr:"address"} ,
  $unset:{flag:""}
   }
 )
 db.c1.find({name:"zs44"})
View Code

6.delete

//全部移除
db.userinfo.deleteMany({})
db.userinfo.deleteMany({age:1})
123
View Code

7.聚合查询

顾名思义就是把数据聚起来,然后统计
语法
  db.集合名称.aggregate([
   {管道:{表达式}}
     ....
])  

常用管道
$group 将集合中的文档分组,用于统计结果
$match 过滤数据,只要输出符合条件的文档
$sort 聚合数据进一步排序
$skip 跳过指定文档数
$limit 限制集合数据返回文档数
常用表达式
$sum 总和 $sum:1同count表示统计
$avg 平均
$min 最小值
$max 最大值

查询例子

use test4
db.c1.insert({_id:1,name:"a",sex:1,age:1})
db.c1.insert({_id:2,name:"a",sex:1,age:2})

统计男生、女生的总年龄
db.c1.aggregate([
{
 $group:{
_id: "$sex",
rs: {$sum: "$age"}
 }
}
])

统计男生、女生的总人数
db.c1.aggregate([
{
 $group:{
_id: "$sex",
rs: {$sum:1}
 }
}
])
求学生总数和平均年龄
db.c1.aggregate([
{
 $group:{
_id: null,
total_num: {$sum:1},
total_avg: {$avg: "$age"}
 }
}
])
查询男生、女生人数,按人数升序
db.c1.aggregate([
{$group:{_id: "$sex",rs: {$sum: 1}}},
{$sort:{rs: -1}}
])
View Code
8.自增id
#创建序列
db.counters.insert({_id:"productid",sequence_value:0}) 
9.创建 Javascript 函数 
现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid
>function getNextSequenceValue(sequenceName){
   var sequenceDocument = 
db.counters.findAndModify(
     {
         query:{_id: sequenceName },
         update: {$inc:{sequence_value:1}},
         "new":true
     });
   return sequenceDocument.sequence_value;
}
View Code
使用 Javascript 函数
接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:
>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Apple iPhone",
   "category":"mobiles"})
>db.products.insert({
   "_id":getNextSequenceValue("productid"),
   "product_name":"Samsung S3",
   "category":"mobiles"})
View Code
就如你所看到的,我们使用 getNextSequenceValue 函数来设置
_id 字段。
为了验证函数是否有效,我们可以使用以下命令读取文档:
>db.products.find()
以上命令将返回以下结果,我们发现 _id 字段是自增长的:
事务
use test
db.createCollection("userinfo") s=db.getMongo().startSession()
s.startTransaction()
s.getDatabase("test").userinfo.insert({name:"a"})
s.commitTransaction()
View Code
数据失效机制
mongodb失效的机制大概是这样的
为集合创建一个indexes(索引)
db.testCollection.ensureIndex( { "Date": 1 }, {expireAfterSeconds: 10 } )
然后确保每次插入数据的时候有该列,mongodb将会自动为你删除
该列
db.testCollection.insert({"Date" : newDate(),"name":"zs","age":18}){ "_id" : 1, "product_name" : "Apple iPhone","category" : "mobiles"}{ "_id" : 2, "product_name" : "Samsung S3","category" : "mobiles" }
 
use test
db.createCollection("userinfo")
s=db.getMongo().startSession()
s.startTransaction()
s.getDatabase("test").userinfo.insert({name:"a"})
s.commitTransaction()
设置的失效列必须为索引并且为日期格式

推荐阅读