1 初始MongoDB MongoDB是一个以JSON为数据模型的文档数据库,文档来自于”JSON Document”,并非一般理解的PDF、WORD文档。是由上市公司MongoDB Inc.开发,位于美国纽约。是一个应用数据库,非关系型数据库,即NOSQL。主要特点:建模可选,JSON数据模型比较适合开发者,横向扩展可以支持很大数据量和并发,理论无上限。MongoDB的文档指的是JSON对象,对应Java中更像是一个Object对象的概念,而不是文件的概念。
MongoDB的使用场景:电商,物联网,内容管理(Web前端),社交,航空业,电信业等。
1.1 MongoDB特点 数据模型不一样:MongoDB是JSON模型。
开发模式不一样:传统的数据库是需要建模的,MongoDB是不要求先建模的,可以按照程序的模型,直接把程序的数据模型直接扔到MongoDB就可以直接保存,支持数据库的操作。
面向对象的数据模型:在Java和Python中都是使用面向对象的方式开发,一般后端返回给前端的数据交互都是JSON,所以MongoDB数据库模型是直接和Java对象吻合的,JSON其实就是一种对象。
1.2 MongoDB VS 关系型数据库
MongoDB
RDBMS
数据模型
文档类型
关系类型
数据库类型
OLTP
OLTP
CRUD操作
MQL/SQL
SQL
高可用
复制集
集群模式
横向扩展能力
通过原生分片完善支持
中间件/应用入侵式
索引支持
B树,全文索引,地理位置索引,多键值索引,TTL索引
B树
开发难度
容易
困难
数据容量
没有理论上限
千万、亿
扩展方式
垂直扩展+水平扩展
垂直扩展
OLTP: OLTP(Online Transaction Processing)数据库,也称交易型数据库,是能够提供实时在线处理事务时保证强一致性(ACID) 的关系型数据库。事务(Transaction)是操作数据库中数据的操作序列,要求保证ACID,即原子性(Atomicity)、 一致性 (Consistency)、隔离性(Isolation)、持久性(Durability)。
OLTP(Online Transaction Processing)) 是用来做前端交互式应用的
OLAP(Online analytical processing) 是在线分析处理,顾名思义就是OLAP是用于数据分析的
2 MongoDB优势
JSON 结构和对象模型接近,开发代码量低
JSON 的动态模型意味着更容易响应新的业务需求
复制集提供99.999% 高可用
分表架构支持海量数据和无缝扩容
3 MongoDB安装与使用 3.1 MongoDB安装 下载地址:https://www.mongodb.com/try/download/community
安装:
1 2 3 4 5 6 7 8 9 10 11 12 13 mkdir -p /data /data/dbmkdir -p /data /data/logscd data curl -O https://fastdl.mongodb.org/linux/mongodblinux-x86_64-rhel70-4.2.24.tgz tar -xvf mongodb-linux-x86_64-rhel70-4.2.24.tgzexport PATH=$PATH :/data/mongodb-linux-x86_64-rhel70-4.2.24/bin vim /etc/profilesource /etc/profilecd /data/mongodb-linux-x86_64-rhel70-4.2.24/bin
修改配置文件:
1 2 3 4 5 6 dbpath = /data/db #数据文件存放目录 logpath = /data/logs/mongodb.log #日志文件存放目录 port = 27017 #端口 fork = true #以守护程序的方式启用,即在后台运行 bind_ip =0.0.0.0 #允许远程访问,或者直接注释,127.0.0.1是只允许本地访问
启动mongodb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mongod --dbpath /data/db --port 27017 --logpath /data/logs/mongod.log --fork -bind_ip 0.0.0.0 mongod -f mongodb.conf mongod pkill mongod mongod --shutdown netstat -nltp | grep mongod ps -ef | grep mongo firewall-cmd --zone=public --add-port=27017/tcp --permanent firewall-cmd --zone=public --add-port=28017/tcp --permanent firewall-cmd --reload firewall-cmd --zone=public --list-ports
浏览器访问:ip:27017
导入样本数据:
1 2 3 4 5 tar -xvf dump.tar.gz mongorestore -h localhost:27017
3.2 基本操作 1 2 3 4 5 6 >use DATABASE_NAME 如果数据库不存在,则创建数据库,否则切换到指定数据库。 >use crud switched to db crud >db crud
3.2.1 使用 insert 完成插入操作 1 2 3 4 5 6 7 8 9 10 11 使用 insert 完成插入操作 操作格式: db.<集合>.insertOne(<JSON 对象>) db.<集合>.insertMany([<JSON 1 >, <JSON 2 >, …<JSON n>]) 示例: db.fruit.insertOne({name : "apple"}) db.fruit.insertMany([ {name : "apple"}, {name : "pear"}, {name : "orange"} ])
3.2.2 使用 find 查询文档 1 2 3 4 5 6 7 8 9 关于 find: find 是 MongoDB 中查询数据的基本指令,相当于 SQL 中的SELECT。 find 返回的是游标。 find 示例: db.movies .find ( { "year" : 1975 } ) db.movies .find ( { "year" : 1989 , "title" : "Batman" } ) db.movies .find ( { $and : [ {"title" : "Batman" }, {"category" : "action" }] } ) db.movies .find ( { $or : [{"year" : 1989}, {"title" :"Batman" }] } ) db.movies .find ( { "title" : /^B/} )
空的查询文档{}会匹配集合的全部内容。若是不指定查询文档,默认就是{}
方法名
作用
linit(n)
限制查询结果返回数量n
skip(n)
跳过指定数目的文档
sort({key:1 or -1})
对查询结果进行排序
explain()
用于获取查询执行过程报告
snapshot()
对查询结果使用快照
count()
查询文档的总数量
游标使用过程:
(1)声明游标:var cursor=db.collectioName.find({query}, {projection})
(2)打开游标:cursor.hasNext()判断游标是否已经取到尽头
(3)读取数据:cursor.Next()取出游标的下一个文档
(4)关闭游标:cursor.close()此步骤可省略,通常为自动关闭,也可 以显示关闭
(5)使用print输出游标结果集
示例:
1.声明游标 var cursor = db.orders.find()
2.使用printjson输出游标结果集: while (cursor.hasNext()) { print(tojson(cursor.next())) }
查询条件对照表
SQL
MQL
a = 1
{ a : 1 }
a <> 1
{ a: {$ne: 1}}
a > 1
{ a: {$gt: 1}}
a >= 1
{ a: {$gte: 1}}
a < 1
{ a: {$lt: 1}}
a <= 1
{ a: {$lte: 1}}
查询逻辑对照表
SQL
MQL
a = 1 ADN b = 1
{a: 1,b: 1} 或{$and: [{a:1},{b: 1}]}
a = 1 OR b = 1
{$or:[{a:1},{b:1}]}
a IS NULL
{a: {$exists: false}}
a IN (1,2,3)
{a:{$in: [1,2,3]}}
查询逻辑逻辑运算符
$lt: 存在并小于
$lte: 存在并小于等于
$gt: 存在并大于
$gte: 存在并大于等于
$ne: 不存在或存在但不等于
$in: 存在并在指定数组中
$nin: 不存在或不在指定数组中
$or: 匹配两个或多个条件中的一个
$and: 匹配全部条件
3.2.3 使用 find 搜索子文档 1 2 3 4 5 6 7 8 9 10 11 12 find 支持使用“field.sub_field”的形式查询子文档。假设有一个文档: db.fruit.insertOne({ name: "apple" , from : { country: "China" , province: "Guangdon" } }) 考虑以下查询的意义: db.fruit.find ( { "from.country" : "China" } ) 上面这条是要查询 要查询子文档,from .country db.fruit.find ( { "from" : {country: "China" } }) 这条要找文档里面有一个from 字段,from 字段的值为country ="China" 如果要查询子文档,必须在子文档里写上路径
3.2.4 使用 find 搜索数组 1 2 3 4 5 6 7 find 支持对数组中的元素进行搜索。假设有一个文档: db.fruit.insert([ { "name" : "Apple" , color : ["red" , "green" ] }, { "name" : "Mango" , color : ["yellow" , "green" ] } ]) 考虑以下查询的意义:db.fruit.find({color : "red" }) db.fruit.find({$or: [{color : "red" }, {color :"yellow" }]})
3.2.5 使用 find 搜索数组中的对象 1 2 3 4 5 6 7 8 9 10 11 考虑以下文档,在其中搜索db .movies.insertOne( { "title" : "Raiders of the Lost Ark" , "filming_locations" : [ { "city" : "Los Angeles" , "state" : "CA" , "country" : "USA" }, { "city" : "Rome" , "state" : "Lazio" , "country" : "Italy" }, { "city" : "Florence" , "state" : "SC" , "country" : "USA" } ] })db .movies.find({"filming_locations.city" : "Rome" }).pretty()
3.2.6 模糊查询Like 1 2 db.movies.find ({"filming_locations.city" : /Rome/ }).pretty() 采用 / / ,中间就是模糊查询的内容,比如:“/ Rome / ”,查询名字包含:Rome,如果是以什么开头就在左边增加^ 反之亦然
3.2.7 正则使用 1 2 {<field>: {$rege x: /pattern/ , $optio ns: '' } } db.movies.find ({"filming_locations.city" : {$rege x:/Rome/ } }).pretty()
3.2.8 使用 find 搜索数组中的对象,相当于是内联外联 1 2 3 4 5 6 在数组中搜索子对象的多个字段时,如果使用 $elemMatch ,它表示必须是同一个子对象满足多个条件。考虑以下两个查询: db.getCollection('movies' ).find ({ "filming_locations.city" : "Rome" , "filming_locations.country" : "USA" }) db.getCollection('movies' ).find ({ "filming_locations" : { $elemMatch :{"city" :"Rome" , "country" : "USA" }}})
3.2.9 控制 find 返回的字段 1 2 3 find 可以指定只返回指定的字段:_id字段必须明确指明不返回,否则默认返回;在 MongoDB 中我们称这为投影(projection); db .movies.find({"category" : "action" },{"_id" :0 (0 代表不返回id), title:1 (1 代表返回title)}) db .movies.find({},{"_id" :0 , title:1 })
3.2.10 使用 remove 删除文档 1 2 3 4 5 6 7 8 remove 命令需要配合查询条件使用; ● 匹配查询条件的的文档会被删除; ● 指定一个空文档条件会删除所有文档; ● 以下示例: db.testcol .remove ( { a : 1 } ) db.testcol .remove ( { a : { $lt : 5 } } ) db.testcol .remove ( {} ) db.testcol .remove ()
3.2.11 使用 update 更新文档 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Update 操作执行格式:db.<集合>.update (<查询条件>, <更新字段>) 以下数据为例: db.fruit.insertMany ([ {name : "apple" }, {name : "pear" }, {name : "orange" } ]) db.fruit.updateOne ({name : "apple" }, {$set : {from :"China" }}) 查询 name 为 apple 的记录,将找到记录的 from 设置为 China 使用 updateOne 表示无论条件匹配多少条记录,始终只更新第一条; 使用 updateMany 表示条件匹配多少条就更新多少条; updateOne/updateMany 方法要求更新条件部分必须具有以下之一,否则将报错:$set /$unset $push /$pushAll /$pop $pull /$pullAll $addToSet db.fruit.updateOne ({name : "apple" }, {from : "China" })
3.2.12 使用 update 更新数组 1 2 3 4 5 6 ● $pus h: 增加一个对象到数组底部 ● $pus hAll: 增加多个对象到数组底部 ● $pop : 从数组底部删除一个对象 ● $pull : 如果匹配指定的值,从数组中删除相应的对象 ● $pullAll : 如果匹配任意的值,从数据中删除相应的对象 ● $addToSet : 如果不存在则增加一个值到数组
3.2.13 使用 drop 删除集合 1 2 3 4 ● 使用 db .<集合>.drop () 来删除一个集合 ● 集合中的全部文档都会被删除 ● 集合相关的索引也会被删除db .colToBeDropped.drop ()
3.2.14 使用 dropDatabase 删除数据库 1 2 3 4 5 6 ● 使用 db.dropDatabase() 来删除数据库 ● 数据库相应文件也会被删除,磁盘空间将被释放use tempDB db.dropDatabase()show collections show dbs
3.3 SpringBoot整合 添加pom依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-mongodb</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > commons-lang</groupId > <artifactId > commons-lang</artifactId > </dependency >
配置文件
1 2 3 4 5 6 7 8 9 10 11 server.port =8084 spring.application.name =mongodb-application spring.data.mongodb.host =47.113.147.179 spring.data.mongodb.port =27017 spring.data.mongodb.database =springboot_db
使用
1 2 @Autowired private MongoTemplate mongoTemplate;
3.4 聚合查询
分析性、统计型的场景、复杂数据的计算和处理
MongoDB 聚合框架(Aggregation Framework)是一个计算框架,它可以:作用在一个或几个集合上;对集合中的数据进行的一系列运算,比如数据的计算;将这些数据转化为期望的形式,比如类型的处理。从效果而言,聚合框架相当于 SQL 查询中的:GROUP BY,LEFT OUTER JOIN,AS 等
3.4.1 管道(Pipeline)和步骤(Stage) 整个聚合运算过程称为管道(Pipeline),它是由多个步骤 (Stage)组成的, 每个管道:
接受一系列文档(原始数据);
每个步骤对这些文档进行一系列运算;
结果文档输出给下一个步骤;
3.4.2 聚合运算的基本格式 1 2 3 4 5 pipeline = [$stage1 , $stage2 , ...$stageN ]; // 这个pipeline 就是一系列的计算步骤组成 db.<COLLECTION>.aggregate( pipeline, { options } );
常见步骤
步骤
作用
SQL等价运算符
$match
过滤
WHERE
$project
投影
AS
$sort
排序
ORDER BY
$group
分组
GROUP BY
$skip/$limit
结果限制
SKIP/LIMIT
$lookup
左外连接
LEFT OUTER JOIN
$unwind
展开数组
$graphLookup
图搜索
$facet/$bucket
分面搜索
常见步骤中的运算符
$match
$project
$group
查询过滤 $eq/ $gt/ $gte/ $lt/ $lte/
选择需要的或者排除不 需要的字段 $map/ $reduce/ $filter
聚合计算 $sum/ $avg
$and/ $or/ $not/ $in
$range
$push/ $addToSet
$geoWithin/ $intersect …
$multipy/ $divide/ $substract/ $add …
$first/ $last/ $max/ $min …
MQL 常用步骤与 SQL 对比
3.4.3 MQL特有步骤 $unwind 在做报表的时候,可能需要把用户的分数展出来,可以利用 MongoDB的 $unwind 把整个数组的数据展出来变成一行一行展示。
3.4.4 MQL特有步骤 $bucket 如果是在做电商目录和产品数量会非常有用,需要统计一下商品,100块钱的商品有多少、200的有多少,这个运算的话就不需要一个个去查询,然后再后面通过union或者是程序代码来汇总了.
3.4.5 MQL 特有步骤 $facet 更高阶的应用,把$bucket 组合起来使用,比如需要统计更多纬度和更复杂的需求的时候,这个$facet ,可以把多个纬度的需求放在同一个查询来完成