与邮政编码数据集的聚合
本文档中的示例将使用 zipcodes
集合。该集合可在以下网址获取:media.mongodb.org/zips.json。使用 mongoimport
将此数据集加载到您的 mongod
实例中。
数据模型
zipcodes
集合中的每个文档均采用以下形式:
{ "_id": "10280", "city": "NEW YORK", "state": "NY", "pop": 5574, "loc": [ -74.016323, 40.710537 ] }
_id
字段会以字符串形式保存邮政编码。city
字段会包含城市名称。一个城市可有多个与其关联的邮政编码,因为该城市的不同区域可能有不同的邮政编码。state
字段会包含两个字母的州缩写名。pop
字段会保存人口数。loc
字段会以经纬度对的形式保存位置。
aggregate()
方法
以下所有示例均使用 mongosh
中的 aggregate()
辅助程序。
aggregate()
方法使用聚合管道将文档处理为聚合结果。一个聚合管道由多个阶段组成,其中每个阶段均会处理沿管道传递的文档。文档会按顺序通过各个阶段。
mongosh
中的 aggregate()
方法提供 aggregate
数据库命令的封装器。请参阅驱动程序文档,了解进行数据聚合操作更惯用的界面。
返回人口超过 1,000 万的州
以下聚合操作返回总人口大于 1,000 万的所有州:
db.zipcodes.aggregate( [ { $group: { _id: "$state", totalPop: { $sum: "$pop" } } }, { $match: { totalPop: { $gte: 10*1000*1000 } } } ] )
在此示例中,聚合管道由 $group
阶段和 $match
阶段组成:
$group
阶段按state
字段对zipcode
集合的文档进行分组,计算针对每个状态的totalPop
字段,并输出每个唯一状态的对应文档。新的州别文档有两个字段:
_id
字段和totalPop
字段。_id
字段包含state
(即按字段划分的群组)的值。totalPop
是计算得出的字段,包含每个州的总人口。为计算该值,$group
使用$sum
操作符为每个州添加人口字段 (pop
)。经过
$group
阶段后,管道中的文档如下所示:{ "_id" : "AK", "totalPop" : 550043 } $match
阶段筛选分组文档,仅输出totalPop
值大于或等于 1,000 万的文档。$match
阶段不改变匹配文档,而是输出未经修改的匹配文档。
此聚合操作的等效 SQL 为:
SELECT state, SUM(pop) AS totalPop FROM zipcodes GROUP BY state HAVING totalPop >= (10*1000*1000)
返回各州的平均城市人口
以下聚合操作将返回每个州的城市平均人口:
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
字段(即_id
文档中的state
字段)对管道中的文档进行分组,使用$avg
表达式计算每个州的平均城市人口 (avgCityPop
),并输出每个州的对应文档。
此聚合操作得到的文档应类似如下内容:
{ "_id" : "MN", "avgCityPop" : 5335 }
按省/市/自治区返回最大城市和最小城市
以下聚合操作会返回每个州按人口计算的最小城市和最大城市:
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" } } } ] )
在此示例中,aggregation pipeline 由一个 $group
阶段、一个 $sort
阶段、另一个 $group
阶段和一个 $project
阶段组成:
第一个
$group
阶段按city
和state
的组合对文档进行分组,计算每个组合的pop
值的sum
,并为每个city
和state
组合输出一个文档。在此管道阶段,文档如下所示:
{ "_id" : { "state" : "CO", "city" : "EDGEWATER" }, "pop" : 13154 } $sort
阶段按照pop
字段值从小到大排列管道中的文档,即递增顺序。此操作不会更改文档。接下来的
$group
阶段会按_id.state
字段(即_id
文档中的state
字段)对现已排序的文档分组,并输出每个状态的对应文档。此阶段还会为每个状态计算以下四个字段。
$group
操作符使用$last
表达式,创建biggestCity
和biggestPop
字段,分别存储人口最多的城市和具体人口数。$group
操作符使用$first
表达式,创建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 } }
[1] | 一个城市可有多个与其关联的邮政编码,因为该城市的不同区域可能有不同的邮政编码。 |