介绍
处理数据库时,任何时候需要提取数据,都需要执行一个称为查询的操作。但是,查询仅返回数据库中已经存在的数据。但是,此汇总操作使您可以分析数据为“零”模式或其他有关数据的信息。
mongoDB聚合管道只是一系列指令,称为阶段,可帮助您执行分类,过滤,分组和转换等操作。
。为什么
聚合框架是灵活的,用于许多不同的数据处理和操纵任务。一些典型的示例用途是:
- 分析
- 实时仪表板
- 准备通过视图显示的数据
- 加入来自不同收藏的数据
- 数据的后处理
- 隐藏敏感数据的数据掩盖
- ... 和更多
提示1:何时使用$set
,$unset
&$project
当您需要从输入记录中保留大多数字段时,您应该使用这些阶段,并且要从输入中添加,更新或删除一小部分字段。
例如,想象一下有类似于以下的用户文档的集合:
// INPUT (a record from the source collection to be operated on by an aggregation)
{
_id: ObjectId("6044faa70b2c21f8705d8954"),
first_name: "Maurice",
last_name: "Moss",
email: "Maurice.Moss@gmail.com",
registered: true,
dob: "1983-08-31T23:59:59.736Z",
age:39,
address: {
street: "123 Fake St",
city: "Springfield",
state: "IL",
zip: "12345"
}
}
然后,想象一下要生成文档的修改版本需要进行聚合管道,如下所示:
// OUTPUT (a record in the results of the executed aggregation)
{
name: "Maurice Moss", // Added a new name field
first_name: "Maurice",
last_name: "Moss",
email: "Maurice.Moss@gmail.com",
registered: true,
dob: ISODate("1983-08-31T23:59:59.736Z"), // Field type converted from text
age:39,
address: {
street: "123 Fake St",
city: "Springfield",
state: "IL",
zip: "12345"
}
}
在这里,以//注释显示,需要稍微修改每个文档的结构,以将dob
文本字段转换为适当的日期字段,并添加一个新的name
字段,设置为“ first_name + last_name
”,对于每个记录。
天真地您可能决定使用$project
阶段构建聚合管道以实现此转换,这可能看起来与以下几个相似:
//BAD
[
{
$project: {
// Modify a field + add a new field
name: { $concat: [ "$first_name", " ", "$last_name" ] },
dob: { $dateFromString: {"dateString": "$dob"} },
// Must now name all the other fields for those fields to be retained
email: 1,
registered: 1,
age: 1,
address: 1,
// Remove _id field
_id: 0
}
}
]
您可以看到,根据输入文档,此管道阶段长度可能会变得很长。由于您使用$project
修改或添加字段,因此您还必须从源记录中明确提及彼此的现有字段以包含。想象一下,如果您的源文档有数百个字段!
更好地实现相同结果的方法是使用$set
和$unset
,如下所示:
[
{$set: {
// Modified + new field
name: { $concat: [ "$first_name", " ", "$last_name" ] },
dob: { $dateFromString: {"dateString": "$dob"} },
}},
{$unset: [
// Remove _id field
_id,
]},
]
请注意,当您在源文档中有数百个字段时,$set
和$unset
的可容易,您只需要修改其中的几个。
当所需的输出文档的形状与输入文档的形状大不相同时,最好使用$project
阶段。当您不需要包含大多数原始字段时,通常会出现这种情况。
提示2:使用解释计划
在编写查询时,重要的是要查看查询的解释计划,以确定您是否使用了适当的索引以及是否需要优化查询。
同样的是聚合管道和查看解释计划的能力。在聚集中,这非常关键,因为您通常倾向于具有更复杂的逻辑。
要查看聚合管道的解释计划,您可以执行诸如以下
之类的命令
const pipeline = [{"$match": {"name": "Jo"}}]
db.users.explain().aggregate(pipeline);
提示3:流媒体与阻塞阶段
执行聚合管道时,数据库引擎从针对源集合生成的初始查询光标中提取记录。然后,它尝试通过聚合管道阶段流式传输每个批次。如果您已经称为_streaming阶段_数据库引擎将处理一批,然后立即将其流式传输到下一阶段。它将无需等待其他批次到达。
但是,有两种类型的阶段必须阻止并等待所有批次到达。因此,它们被称为阻止阶段
- $ sort
- $ group
如果您考虑一下,很明显他们必须阻止。因为,如果阶段仅sort/group
每个批处理内容而不等待其他批次,则输出记录将在批处理中进行排序,但不能整个结果设置。
这些不可避免的阻塞阶段通过减少并发来增加您的执行时间。如果不小心使用,则不可避免地会大幅度增加记忆消耗和缓慢的吞吐量。
提示4:匹配过滤器出现在管道中
根据MongoDB文档,他们的引擎将尽最大努力在运行时优化管道。特别是,将$match
阶段移至管道顶部之类的步骤。
但是,可能并非总是有可能为数据库引擎推广$match
过滤器。
有时,在稍后在管道中定义了$match
阶段,以在管道在早期阶段计算的字段上执行过滤器。管道的原始输入集合中不存在计算的字段。
因此,您作为开发人员,必须考虑并将$match
阶段提升到最高水平,而不是使用早期阶段的计算字段。
感谢您的阅读。您可以在MongoDB文档中找到更多最佳实践。