本文档中的示例使用 zipcodes集合。该集合位于:媒体.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] | 一个城市可有多个与其关联的邮政编码,因为该城市的不同区域可能有不同的邮政编码。 |