本文档提供了许多实际示例,展示了聚合框架的功能。
使用邮政编码数据集的 聚合示例使用了包含美国所有邮政编码和人口的公开数据集。此数据位于:zips.json。
要求
让我们检查一下是否所有内容都已安装。
使用以下命令将 zips.json数据集加载到mongod实例:
$ mongoimport --drop -d test -c zipcodes zips.json
让我们使用MongoDB shell验证所有内容是否已成功导入。
$ mongo test connecting to: test > db.zipcodes.count() 29467 > db.zipcodes.findOne() { "_id" : "35004", "city" : "ACMAR", "loc" : [ -86.51557, 33.584132 ], "pop" : 6055, "state" : "AL" }
使用邮政编码数据集的聚合
此集合中的每个文档均采用以下形式:
{ "_id" : "35004", "city" : "Acmar", "state" : "AL", "pop" : 6055, "loc" : [-86.51557, 33.584132] }
在这些文档中:
_id
字段会将邮政编码以string形式保存。city
字段包含城市名称。state
字段会包含两个字母的州缩写名。pop
字段会保存人口数。loc
字段会以[latitude, longitude]
数组的形式保存位置。
人口超过10百万的州
要获取人口超过10百万的所有州,请使用以下聚合管道:
static void print_pipeline (mongoc_collection_t *collection) { mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_t *pipeline; char *str; pipeline = BCON_NEW ("pipeline", "[", "{", "$group", "{", "_id", "$state", "total_pop", "{", "$sum", "$pop", "}", "}", "}", "{", "$match", "{", "total_pop", "{", "$gte", BCON_INT32 (10000000), "}", "}", "}", "]"); cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_canonical_extended_json (doc, NULL); printf ("%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); } mongoc_cursor_destroy (cursor); bson_destroy (pipeline); } int main (void) { mongoc_client_t *client; mongoc_collection_t *collection; const char *uri_string = "mongodb://localhost:27017/?appname=aggregation-example"; mongoc_uri_t *uri; bson_error_t error; mongoc_init (); uri = mongoc_uri_new_with_error (uri_string, &error); if (!uri) { fprintf (stderr, "failed to parse URI: %s\n" "error message: %s\n", uri_string, error.message); return EXIT_FAILURE; } client = mongoc_client_new_from_uri (uri); if (!client) { return EXIT_FAILURE; } mongoc_client_set_error_api (client, 2); collection = mongoc_client_get_collection (client, "test", "zipcodes"); print_pipeline (collection); mongoc_uri_destroy (uri); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); return EXIT_SUCCESS; }
您应该会看到如下结果:
{ "_id" : "PA", "total_pop" : 11881643 } { "_id" : "OH", "total_pop" : 10847115 } { "_id" : "NY", "total_pop" : 17990455 } { "_id" : "FL", "total_pop" : 12937284 } { "_id" : "TX", "total_pop" : 16986510 } { "_id" : "IL", "total_pop" : 11430472 } { "_id" : "CA", "total_pop" : 29760021 }
上述聚合管道由两个管道操作符构建: $group
和$match
。
$group
管道操作符需要_id字段,我们在其中指定分组;剩余字段指定如何生成复合值,并且必须使用群组聚合函数之一: $addToSet
、 $first
、 $last
、 $max
、 $min
、 $avg
、 $push
、 $sum
。 $match
管道操作符语法与读取操作查询语法相同。
$group
进程会读取所有文档,并为每个状态创建一个单独的文档,示例:
{ "_id" : "WA", "total_pop" : 4866692 }
total_pop
字段使用 $sum聚合函数对源文档中所有 Pop 字段的值求和。
$group
创建的文档通过管道传送到$match
管道操作符。 它返回total_pop
字段的值大于或等于10万的文档。
各州平均城市人口
要获取每个城市平均人口最多的前三个州,请使用以下聚合:
pipeline = BCON_NEW ("pipeline", "[", "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}", "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}", "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}", "{", "$limit", BCON_INT32 (3) "}", "]");
此聚合管道会生成:
{ "_id" : "DC", "avg_city_pop" : 303450.0 } { "_id" : "FL", "avg_city_pop" : 27942.29805615551 } { "_id" : "CA", "avg_city_pop" : 27735.341099720412 }
上述聚合管道由三个管道操作符构建: $group
、 $sort
和$limit
。
第一个$group
操作符创建以下文档:
{ "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 }
请注意, $group
操作符不能使用除_id
字段之外的嵌套文档。
第二个$group
使用这些文档创建以下文档:
{ "_id" : "FL", "avg_city_pop" : 27942.29805615551 }
这些文档按avg_city_pop
字段降序排序。 最后, $limit
管道操作符返回排序设立的前3文档。