MongoDB提供了强大的数据分析功能,支持使用汇总框架进行本地分析。
1.Pipelines, Stages, Tunables(可调整)
聚合框架是MongoDB中允许您执行的一组分析工具对一个或多个集合中的文档进行分析。
聚合框架基于管道的概念。 聚合管道是指我们从MongoDB集合中获取输入,并从中传递文档通过一个或多个阶段进行收集,每个阶段执行不同的步骤在其输入上进行操作,各个阶段作为输入之前的任何阶段都作为输入输出。 如果您愿意,所有阶段的输入和输出都是文件流。
如果您熟悉Linux shell中的管道,比如bash,这是一个非常相似的想法stage有一个它所做的特定工作。它期望一个特定形式的文档并生成一个特定的输出,它本身就是一个文档流。在管道的末尾,我们可以访问对于输出,与执行find查询的方式大致相同意味着我们得到一个文档流,然后我们可以做额外的工作,是否它可以创建某种类型的报告、生成网站或其他类型的任务。
现在,让我们深入一点,考虑各个阶段聚合管道是一个数据处理单元,正如我提到的,这个阶段需要一个输入流,一次一个文档,一次处理一个文档,并生成一个输出流,一次一个文件。
每个阶段都提供一组旋钮或可调项,我们可以控制这些旋钮或可调项,以将阶段参数化为执行我们感兴趣的任务。阶段执行一般任务某种目的任务,我们参数化特定集合的阶段,我们是与这些文件合作,并确切地说明我们希望这一阶段如何处理这些文件。
这些可调参数通常采用运算符的形式,我们可以提供这些运算符来修改字段,执行算术运算重塑文档,或者执行某种累加任务作为其他的东西。
在我们深入研究一些具体示例之前,我想介绍在您开始使用管道时,请记住这些管道特别重要。通常,我们希望在一个管道中多次包含同一类型的stage。例如,我们可能需要执行一个初始过滤器,这样就不必传递整个收集到我们的管道中。但是之后,经过一些额外的处理,我们可能希望进一步筛选,应用一组不同的条件。
总而言之,管道与MongoDB集合一起工作,它对其输入执行不同的数据处理任务,并生成文档作为输出传递到下一个阶段。最后,在最后,一个管道产生输出,我们可以这样做在很多情况下,为了执行分析,我们将在一个单独的管道中多次包含同一类型的阶段。
2.阶段入门:熟悉的操作
作为开发聚合管道的第一步,我们将考虑构建一些管道这涉及到你已经熟悉的操作。为此,我们来看看match,project, sort, skip, 和 limit stages.
为了完成这些聚合示例,我们将使用一组公司数据,让我们看一个基于包含Facebook,Inc.数据的文档的示例,我们有一个集合,其中有许多字段指定公司的详细信息,例如公司成立时的员工人数。
此外,还有一些领域可以用于公司的融资,这一点很重要公司的里程碑,无论公司是否已通过首次公开发行(IPO),如果是,IPO的细节。
db.companies.insert(
{
"_id" : "52cdef7c4bab8bd675297d8e",
"name" : "Facebook",
"category_code" : "social",
"founded_year" : 2004,
"description" : "Social network",
"funding_rounds" : [{
"id" : 4,
"round_code" : "b",
"raised_amount" : 27500000,
"raised_currency_code" : "USD",
"funded_year" : 2006,
"investments" : [
{
"company" : null,
"financial_org" : {
"name" : "Greylock Partners",
"permalink" : "greylock"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "Meritech Capital Partners",
"permalink" : "meritechcapitalpartners"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "Founders Fund",
"permalink" : "foundersfund"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "SV Angel",
"permalink" : "svangel"
},
"person" : null
}
]
},
{
"id" : 2197,
"round_code" : "c",
"raised_amount" : 15000000,
"raised_currency_code" : "USD",
"funded_year" : 2008,
"investments" : [
{
"company" : null,
"financial_org" : {
"name" : "European Founders Fund",
"permalink" : "europeanfoundersfund"
},
"person" : null
}
]
}],
"ipo" : {
"valuation_amount" : NumberLong("104000000000"),
"valuation_currency_code" : "USD",
"pub_year" : 2012,
"pub_month" : 5,
"pub_day" : 18,
"stock_symbol" : "NASDAQ:FB"
}
})
(1).作为我们的第一个聚合示例,让我们做一个简单的过滤器来查找成立于2004年。
db.companies.aggregate([
{$match: {founded_year: 2004}},
])
这相当于以下使用find查询的操作。
db.companies.find({founded_year: 2004})
现在,让我们在管道中添加一个project阶段,以便将输出减少到每个文档。我们排除了_id,但包括名称和创建年份。语句如下
db.companies.aggregate([
{$match: {founded_year: 2004}},
{$project: {
_id: 0,
name: 1,
founded_year: 1
}}
])
(2).在原来的基础上增加limit
db.companies.aggregate([
{$match: {founded_year: 2004}},
{$limit: 5},
{$project: {
_id: 0,
name: 1}}
])
下面这个查询与上面效果是一样的:
db.companies.aggregate([
{$match: {founded_year: 2004}},
{$project: {
_id: 0,
name: 1}},
{$limit: 5}
])
(3).如果有排序问题话,那么sort应该要在limit之前
db.companies.aggregate([
{ $match: { founded_year: 2004 } },
{ $sort: { name: 1} },
{ $limit: 5 },
{ $project: {
_id: 0,
name: 1 } }
])
(4).在上面的基础上增加skip
db.companies.aggregate([
{$match: {founded_year: 2004}},
{$sort: {name: 1}},
{$skip: 10},
{$limit: 5},
{$project: {
_id: 0,
name: 1}},
])
3.Expressions(表达式)
聚合框架支持许多不同类型的表达式:
Boolean 表达式允许我们使用and,or,而不是其他表达式。
Set 表达式允许我们将数组作为集合来处理两个或多个集合的交集或并集。我们也可以取两个集合的差和执行许多其他设置操作。
Comparison 比较表达式使我们能够表达许多不同类型的范围过滤器。
Arithmetic 算术表达式使我们能够计算ceiling、floor、natural log、log,以及简单的算术运算,如乘法、除法、加法和减法。我们甚至可以执行更复杂的操作,例如计算a的平方根值。
String 字符串表达式允许我们连接、查找子字符串、执行必须执行的操作使用大小写和文本搜索操作。
Array 数组表达式为操作数组提供了很多功能,包括过滤数组元素、切片数组或只是从特定数组中获取一系列值。
Variable 变量表达式允许我们处理文字,用于分析日期值的表达式和条件表达式。
Accumulators 累加器提供计算和、描述性统计和许多其他功能值的类型。
4.Project Stage 和 Reshaping Documents
我们在聚合管道中看到了一些简单的例子。现在让我们看看更复杂一些的。
(1).嵌套字段
db.companies.aggregate([
{$match: {"funding_rounds.investments.financial_org.permalink": "greylock" }},
{$project: {
_id: 0,
name: 1,
ipo: "$ipo.pub_year",
valuation: "$ipo.valuation_amount",
funders: "$funding_rounds.investments.financial_org.permalink"
}}
]).pretty()
插入Facebook的基础数据
db.companies.insert(
{
"name" : "Facebook",
"category_code" : "social",
"founded_year" : 2004,
"description" : "Social network",
"funding_rounds" : [{
"id" : 4,
"round_code" : "b",
"raised_amount" : 27500000,
"raised_currency_code" : "USD",
"funded_year" : 2006,
"investments" : [
{
"company" : null,
"financial_org" : {
"name" : "Greylock Partners",
"permalink" : "greylock"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "Meritech Capital Partners",
"permalink" : "meritechcapitalpartners"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "Founders Fund",
"permalink" : "foundersfund"
},
"person" : null
},
{
"company" : null,
"financial_org" : {
"name" : "SV Angel",
"permalink" : "svangel"
},
"person" : null
}
]
},
{
"id" : 2197,
"round_code" : "c",
"raised_amount" : 15000000,
"raised_currency_code" : "USD",
"funded_year" : 2008,
"investments" : [
{
"company" : null,
"financial_org" : {
"name" : "European Founders Fund",
"permalink" : "europeanfoundersfund"
},
"person" : null
}
]
}],
"ipo" : {
"valuation_amount" : NumberLong("104000000000"),
"valuation_currency_code" : "USD",
"pub_year" : 2012,
"pub_month" : 5,
"pub_day" : 18,
"stock_symbol" : "NASDAQ:FB"
}
})
再次查询
db.companies.aggregate([
{$match: {"funding_rounds.investments.financial_org.permalink": "greylock" }},
{$project: {
_id: 0,
name: 1,
ipo: "$ipo.pub_year",
valuation: "$ipo.valuation_amount",
funders: "$funding_rounds.investments.financial_org.permalink"
}}
]).pretty()