MongoDB入门

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优势

  1. JSON 结构和对象模型接近,开发代码量低
  2. JSON 的动态模型意味着更容易响应新的业务需求
  3. 复制集提供99.999% 高可用
  4. 分表架构支持海量数据和无缝扩容

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/db
mkdir -p /data /data/logs
cd data

#https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.24.tgz
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.tgz

#设置环境变量
export PATH=$PATH:/data/mongodb-linux-x86_64-rhel70-4.2.24/bin
vim /etc/profile
source /etc/profile
cd /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 #以守护程序的方式启用,即在后台运行
#auth=true #需要认证。如果放开注释,就必须创建MongoDB的账号,使用账号与密码才可远程访问,第一次安装建议注释
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
# 以command line 设置参数的方式启动
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"} ) //多条件and查询
db.movies.find( { $and : [ {"title" : "Batman"}, {"category" : "action" }] } ) // and的另一种形式
db.movies.find( { $or: [{"year" : 1989}, {"title" :"Batman"}] } ) //多条件or查询
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" }
]
})
// 查找城市是 Rome 的记录
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>: {$regex: /pattern/, $options: ''} }
db.movies.find({"filming_locations.city": {$regex:/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 } ) // 删除a等于1的记录
db.testcol.remove( { a : { $lt : 5 } } ) // 删除a小于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
$push: 增加一个对象到数组底部
$pushAll: 增加多个对象到数组底部
$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 // No collections
show dbs // The db is gone

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
## mongodb配置
spring.data.mongodb.host=47.113.147.179
spring.data.mongodb.port=27017
#spring.data.mongodb.username=
#spring.data.mongodb.password=
spring.data.mongodb.database=springboot_db
#spring.data.mongodb.uri=mongodb://name:password@localhost:27017/test

使用

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)组成的, 每个管道:

  1. 接受一系列文档(原始数据);
  2. 每个步骤对这些文档进行一系列运算;
  3. 结果文档输出给下一个步骤;

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 ,可以把多个纬度的需求放在同一个查询来完成


MongoDB入门
http://www.zivjie.cn/2023/05/13/数据库/MongoDB/MongoDB入门/
作者
Francis
发布于
2023年5月13日
许可协议