目录
MongoDB索引Index
聚合操作
通过聚合操作可以处理多个文档,并返回计算后的结果。
- 对多个文档进行分组
- 对分组的文档执行操作并返回单个结果
- 分析数据变化
聚合管道
分别由多个阶段来处理文档,每个阶段的输出是下个阶段的输入, 返回的是一组文档的处理结果,例如,total、average、 maxmium、minimium。
插入下列数据,供聚合操作用
db.orders.insertMany( [
{ _id: 0, name: "Pepperoni", size: "small",price: 19,
quantity: 10, date: ISODate( "2030-03-13T08:14:30Z" ) },
{ _id: 1, name: "Pepperoni", size: "medium",price: 20,
quantity: 20, date : ISODate( "2030-03-13T09:13:24Z" ) },
{ _id: 2, name: "Pepperoni", size: "large",price: 21,
quantity: 30, date : ISODate( "2030-03-17T09:22:12Z" ) },
{ _id: 3, name: "Cheese", size: "small",price: 12,
quantity: 15, date : ISODate( "2030-03-13T11:21:39.736Z" ) },{ _id: 4, name: "Cheese",
size: "medium", price: 13,
quantity:50, date : ISODate( "2031-01-12T21:23:13.331Z" ) }, { _id: 5, name:"Cheese", size: "large", price: 14,
quantity: 10, date : ISODate( "2031-01-12T05:08:13Z" ) },
{ _id: 6, name: "Vegan", size: "small",price: 17,
quantity: 10, date : ISODate( "2030-01-13T05:08:13Z" ) },
{ _id: 7, name: "Vegan", size: "medium",price: 18,
quantity: 10, date : ISODate( "2030-01-13T05:10:13Z" ) }
] )
计算尺寸为medium的订单中,每种类型的订单数量
db.orders.aggregate( [
// Stage 1: 匹配size:"medium"的文档
{
$match: { size: "medium" }
},
// Stage 2: 根据name统计过滤后的文档,并把"quantity"值相加
{
$group: { _id: "$name", totalQuantity: {$sum: "$quantity" } }
}
] )
输出结果:
[
{ _id: 'Cheese', totalQuantity: 50 },
{ _id: 'Vegan', totalQuantity: 10 },
{ _id: 'Pepperoni', totalQuantity: 20 }
]
更复杂的例子:
db.orders.aggregate( [
// Stage 1: 根据日期范围过滤
{
$match:
{
"date": { $gte: new ISODate( "2030-01-01" ), $lt: new ISODate( "2030-01-30" ) }
}
},
// Stage 2: 对过滤后文档以日期为条件进行分组并计算
{
$group:
{
_id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
totalOrderValue: { $sum: { $multiply:[ "$price", "$quantity" ] } },
averageOrderQuantity: { $avg:"$quantity" }
}
},
// Stage 3: 按照订单价值倒序排列文档
{
$sort: { totalOrderValue: -1 }
}
] )
计算结果:
{ "_id" : "2030-01-13", "totalOrderValue" : 350, "averageOrderQuantity" : 10 }
统计集合中文档数量
db.collection.count()
根据指定的字段进行过滤,去掉重复的文档
db.collection.distinct()
聚合管道顺序优化
聚合管道在执行的过程中有一个优化的阶段,以提高性能。
$addFields: {
maxTime: { $max: "$times" },
minTime: { $min: "$times" }
} },
{ $project: {
_id: 1, name: 1, times: 1, maxTime: 1,minTime: 1,
avgTime: { $avg: ["$maxTime", "$minTime"] }
} },
{ $match: {
name: "Joe Schmoe",
maxTime: { $lt: 20 },
minTime: { $gt: 5 },
avgTime: { $gt: 7 }
} }
优化思路:优化器把$match阶段分成了4个独立的过滤器,尽可能 把过滤器放在$project操作前面,优化后的聚合管道如下:
{ $match: { name: "Joe Schmoe" } },
{ $addFields: {
maxTime: { $max: "$times" },
minTime: { $min: "$times" }
} },
{ $match: { maxTime: { $lt: 20 }, minTime: { $gt: 5 } } },
{ $project: {
_id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
avgTime: { $avg: ["$maxTime", "$minTime"] }
} },
{ $match: { avgTime: { $gt: 7 } } }
再例如:
{ $sort: { age : -1 } },
{ $match: { status: 'A' } }
优化后:
{ $match: { status: 'A' } },
{ $sort: { age : -1 } }
限制事项
- 返回结果集不能超过16M字节
- 单个管道中的stage数量不能超过1000个(MongoDB 5.0)
实时效果反馈
1.下列聚合操作命令中有错的是哪个?
A $sum、$avg、$unset
B $min 、$push、$first
C $last、$group、$project
D $match、$limit、$max
MongoDB索引Index
索引概述
索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指 向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当 于图书的目录,可以根据目录中的页码快速找到所需的内容。索引目标是提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scan every document in a collection),数据量大时严重降低 了查询效率。默认情况下Mongo在一个集(collection)创建时, 自动地对集合的_id创建了唯一索引。
索引类型
单键索引
MongoDB默认所有的集合在_id字段上有一个索引。 下图是一个在score字段上建立的升序/降序索引示意图。
创建一个名为records的集合,并插入下面的数据
{
"_id": ObjectId("180c06a4ad577233f97tf825"),
"score": 356,
"location": { province: "Hebei", city: "Tangshan" }
}
创建索引,1代表升序,-1代表降序
db.records.createIndex( { score: 1 } )
在内嵌字段上建立索引
db.records.createIndex( { "location.province": 1 } )
在内嵌文档上建立索引
db.records.createIndex( { location: 1 } )
复合索引
复合索引是指单个索引结构指向多个字段,下图展示了在两个字段 上建立索引
使用下面的数据来创建一个复合索引
{
"item": "Banana",
"category": ["food", "produce", "grocery"],
"location": "4th Street Store",
"stock": 4,
"type": "cases"
}
在item和stock字段上建立升序索引
db.products.createIndex( { "item": 1, "stock": 1 } )
复习:
文件上传_SpringBoot基于FastDFS实现
引入Thymeleaf视图解析器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
下载wangEditor富文本编辑器
为何选择 wangEditor
简洁、轻量级、文档齐全
万星项目 Github Star 1w+
npm 周下载量 1w+
CDN 月下载量百万+(来自 jsdelivr)
QQ 群及时答疑
开源团队维护,非个人单兵作战
编写index页面
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>wangEditor demo</title>
</head>
<body>
<div id="div1">
<p>欢迎使用 <b>wangEditor</b> 富文本编辑器
</p>
</div>
<script type="text/javascript" th:src="@{wangEditor.min.js}"
src="../static/wangEditor.min.js"></script>
<script type="text/javascript">
const E = window.wangEditor
const editor = new E('#div1')
//设置文件上传的参数名称
editor.config.uploadFileName = 'files'
// 配置 server 接口地址
editor.config.uploadImgServer = '/upload/uploadMoreImage.do'
// 2M
editor.config.uploadImgMaxSize = 2 *1024 * 1024
editor.config.uploadImgAccept = ['jpg','jpeg', 'png', 'gif', 'bmp', 'webp']
// 一次最多上传 5 个图片
editor.config.uploadImgMaxLength = 5
editor.create()
</script>
</body>
</html>
编写Controller接口
@RestController
@RequestMapping("/upload")
public class UoloadToFastDFSController {
//fastdfs存储节点的客户端对象
@Autowired
private FastFileStorageClient fastFileStorageClient;
@GetMapping("/upload")
public void uploadMoreImage(MultipartFile[] files){
//判断是否上传图片
if(files != null && files.length != 0 ){
//遍历上传图片
for (MultipartFile multipartFile : files) {
//获取上传文件名
String filename = multipartFile.getOriginalFilename();
//获取最后一个“.”的下标,并获取从这个下标的下一个下标开始后的字符作为文件后缀
String fileSuffix = filename.substring(filename.lastIndexOf(".")+ 1);
StorePath storePath = null;
try {
//上传文件
storePath = fastFileStorageClient.uploadFile(multipartFile.getInputStream(),multipartFile.getSize(), fileSuffix, null);
} catch (IOException e) {
e.printStackTrace();
}
//打印返回的文件在存储节点的唯一标识
System.out.println(storePath.getFullPath());
}
}
}
}
FastDFS集成Nginx
Nginx服务器是一个高性能的web服务器与反向代理服务器。
FastDFS集成Nginx的2个原因
1 为分布式文件系统提供Http服务支持
通过Nginx的web服务代理访问分布式文件系统的存储节点,从而实 现通过http请求访问存储节点资源。
注意: src 属性值图像文件的 URL。也就是引用该图像的文件的的绝对路径或相对路径。
1 解决复制延迟问题
由于FastDFS的同卷的存储节点之间需要同步,当文件尚未同步完成时,访问请求到达改节点,获取的数据将是未同步完的不完整数 据,即为复制延迟问题。通过Nginx检测请求的存储节点的数据, 若该存储节点的数据尚未同步完成,则将请求转发至数据的原存储节点,从而解决复制延迟问题。
实时学习反馈
1.FastDFS集成Nginx主要目的正确的是____。
A 为分布式文件系统提供Http服务支持
B 解决复制延迟问题
C 以上都是正确