进入MongoDB中文手册(4.2版本)目录
本文档中的示例使用zipcodes集合。该集合位于: media.mongodb.org/zips.json。使用mongo import将该数据集加载到您的mongod实例中。
1 数据模型
zipcodes集合中的每个文档都具有以下格式:
{
"_id": "10280",
"city": "NEW YORK",
"state": "NY",
"pop": 5574,
"loc": [
-74.016323,
40.710537
]
}
- _id字段将邮政编码保存为字符串。
- city字段保存城市名称。一个城市可以具有多个与之相关的邮政编码,因为该城市的不同部分可以分别具有不同的邮政编码。
- state字段保存州的两个字母缩写。
- pop字段保存人口数量。
- loc字段将位置保存为经度纬度对。
2 aggregate()方法
以下所有示例均在mongoShell中使用aggregate()方法。
aggregate()方法使用聚合管道将文档处理为聚合结果。一个聚合管道由阶段组成,有每个阶段在文件经过管道的时候处理文件。文件依次经过各个阶段。
mongo shell中的aggregate()方法为aggregate数据库命令提供了包装。有关用于数据聚合操作的详细的接口,请参见驱动程序的文档 。
3 返回人口超过1000万的州
以下聚合操作将返回总人口超过1000万的所有州:
db.zipcodes.aggregate( [
{ $group: { _id: "$state", totalPop: { $sum: "$pop" } } },
{ $match: { totalPop: { $gte: 10*1000*1000 } } }
] )
在此示例中,聚合管道包括$group以及紧跟其后的$match阶段:
- $group阶段将zipcode集合按state字段分组文档,totalPop为每个周计算字段,并为每个唯一的州输出文档。
新的每个州的文档有两个字段:_id字段和totalPop字段。该_id字段包含州的值,即按字段分组。该totalPop字段是包含每个州的总人口的计算字段。$group使用$sum运算符为每个州添加人口字段pop来计算totalPop字段的值。
在$group阶段之后,管道中的文档类似于以下内容:{ "_id" : "AK", "totalPop" : 550043 }
- $match阶段过滤这些分组的文档且仅输出totalPop值大于或等于1000万的那些文档。$match阶段不会更改匹配的文档,但会输出未修改的匹配文档。
此聚合操作的等效SQL为:
SELECT state, SUM(pop) AS totalPop
FROM zipcodes
GROUP BY state
HAVING totalPop >= (10*1000*1000)
也可以看看
4 返回各州城市平均人口数
以下聚合操作返回每个州的城市平均人口:
db.zipcodes.aggregate( [
{ $group: { _id: { state: "$state", city: "$city" }, pop: { $sum: "$pop" } } },
{ $group: { _id: "$_id.state", avgCityPop: { $avg: "$pop" } } }
] )
在这个例子中,聚集管道由$group阶段以及接着是的另一个$group阶段组成:
- 第一个$group阶段根据city和state的组合分组文档,使用$sum表达式来计算每个组合的人口,并且每个city和state组合输出一个文档。 1
在管道中的此阶段之后,文档类似于以下内容:{ "_id" : { "state" : "CO", "city" : "EDGEWATER" }, "pop" : 13154 }
- 第二个$group阶段按_id.state字段(即文档state内部的字段_id)对管道中的文档进行分组,使用$avg表达式计算每个州的平均城市人口avgCityPop,并每个州输出一个文档。
此聚合操作产生的文档类似于以下内容:
{
"_id" : "MN",
"avgCityPop" : 5335
}
也可以看看
5 按州返回最大和最小城市
以下聚合操作将按人口返回每个州的最小和最大城市:
db.zipcodes.aggregate( [
{ $group:
{
_id: { state: "$state", city: "$city" },
pop: { $sum: "$pop" }
}
},
{ $sort: { pop: 1 } },
{ $group:
{
_id : "$_id.state",
biggestCity: { $last: "$_id.city" },
biggestPop: { $last: "$pop" },
smallestCity: { $first: "$_id.city" },
smallestPop: { $first: "$pop" }
}
},
// the following $project is optional, and
// modifies the output format.
{ $project:
{ _id: 0,
state: "$_id",
biggestCity: { name: "$biggestCity", pop: "$biggestPop" },
smallestCity: { name: "$smallestCity", pop: "$smallestPop" }
}
}
] )
在此示例中,聚合管道由一个$group阶段,一个$sort阶段,另一个$group阶段和一个$project阶段组成:
- 第一$group阶段通过city和state的组合分组文档,为每个组合计算spop值的总和,并且每个city和state组合输出一个文档。
在管道的此阶段,文档类似于以下内容:{ "_id" : { "state" : "CO", "city" : "EDGEWATER" }, "pop" : 13154 }
- $sort阶段根据pop字段值对管道中文件排序,从最小到最大; 即递增排序。此操作不会更改文档。
- 下一个$group阶段按_id.state字段(即文档state内部的字段 _id)对现有排序的文档进行分组,并为每个州输出一个文档。
该阶段还将为每个州计算以下四个字段。使用$last表达式,$group运算符创建biggestCity和biggestPop字段,用于存储人口最多的城市和人口。使用$first表达式,$group运算符创建smallestCity和smallestPop字段,用于存储人口最少的城市和人口。
在管道的此阶段,这些文档类似于以下内容:{ "_id" : "WA", "biggestCity" : "SEATTLE", "biggestPop" : 520096, "smallestCity" : "BENGE", "smallestPop" : 2 }
- 最后的$project阶段重命名_id字段为state和移动biggestCity,biggestPop, smallestCity,和smallestPop分别成为biggestCity和smallestCity的嵌入文档。
此聚合操作的输出文档类似于以下内容:
{
"state" : "RI",
"biggestCity" : {
"name" : "CRANSTON",
"pop" : 176404
},
"smallestCity" : {
"name" : "CLAYVILLE",
"pop" : 45
}
}
一个城市可以具有多个与之相关的邮政编码,因为该城市的不同部分可以分别具有不同的邮政编码 ↩︎