猿教程 Logo

.Net连接MongoDb:更多聚合类型

介绍

在上一篇文章中,我们研究了如何向MongoDb聚合管道添加多个阶段。 我们看到,扩展管道的阶段数组很简单直接。 重要的是要记住,每个阶段都会对前一阶段生成的文件进行操作。 我们也可以在同一个舞台类型中多次显示出来,即没有限制,我们只能在一个管道中只有一个$组操作。 各个阶段也可以按各种顺序出现,我们也不必遵循一些类型的排序。

在这篇文章中,我们将继续下去,再看几个聚合算子和示例。

第一和最后

我们现在知道如何使用$ sort运算符对文档的结果集进行排序。 排序后的额外步骤可以是选择文档的第一个或最后一个文档。 这对于诸如“马萨诸塞州最大的城市”或“哪位学生数学成绩最差”的查询很有用。

我们尝试从邮政编码集合中找到每个州最大的城市。 请记住,城市可以在邮政编码集合中多次出现,因为城市可以有多个邮政编码。 因此,第一阶段将按国家和城市进行分组,我们总结每个城市的人口:

db.zipcodes.aggregate([
{$group : { "_id" : {"state" : "$state", "city" : "$city"}, "population"  : {$sum : "$pop"}}}
])

接下来我们根据国家和人口对文件进行排序:

db.zipcodes.aggregate([
{$group : { "_id" : {"state" : "$state", "city" : "$city"}, "population"  : {$sum : "$pop"}}},
{$sort: {"_id.state" : 1, "population" : -1}}
])

现在我们可以在第二个分组阶段为每个状态选择第一个文档。 我们将按城市和人口选择第一份文件:

db.zipcodes.aggregate([
{$group : { "_id" : {"state" : "$state", "city" : "$city"}, "population"  : {$sum : "$pop"}}},
{$sort: {"_id.state" : 1, "population" : -1}},
{$group: {"_id" : {"state" : "$_id.state"}, "largest_city" : {$first: "$_id.city"}, "population" : {$first: "$population"}}}
])

以下是一组示例文档,以显示我们现在的位置:

{ "_id" : { "state" : "PA" }, "largest_city" : "PHILADELPHIA", "population" : 1610956 }
{ "_id" : { "state" : "CO" }, "largest_city" : "DENVER", "population" : 451182 }
{ "_id" : { "state" : "OH" }, "largest_city" : "CLEVELAND", "population" : 536759 }
{ "_id" : { "state" : "AZ" }, "largest_city" : "PHOENIX", "population" : 890853 }
{ "_id" : { "state" : "KY" }, "largest_city" : "LOUISVILLE", "population" : 288058 }

第二个分组阶段似乎弄乱了第一个排序阶段的排序,所以让我们添加另一个排序,并按状态排序文档:

db.zipcodes.aggregate([
{$group : { "_id" : {"state" : "$state", "city" : "$city"}, "population"  : {$sum : "$pop"}}},
{$sort: {"_id.state" : 1, "population" : -1}},
{$group: {"_id" : {"state" : "$_id.state"}, "largest_city" : {$first: "$_id.city"}, "population" : {$first: "$population"}}},
{$sort : {"_id.state" : 1}}
])

它现在按状态排序。

我们还可以在最后引入一个投影舞台,以便使文档更加整洁。 我们摆脱了_id字段,并替换为“state”字段:

db.zipcodes.aggregate([
{$group : { "_id" : {"state" : "$state", "city" : "$city"}, "population"  : {$sum : "$pop"}}},
{$sort: {"_id.state" : 1, "population" : -1}},
{$group: {"_id" : {"state" : "$_id.state"}, "largest_city" : {$first: "$_id.city"}, "population" : {$first: "$population"}}},
{$sort : {"_id.state" : 1}},
{$project : {"_id" : 0, "state" : "$_id.state" ,"largest_city" : 1, "population": 1}}
])

以下是一个示例结果集:

{ "largest_city" : "ANCHORAGE", "population" : 183987, "state" : "AK" }
{ "largest_city" : "BIRMINGHAM", "population" : 242606, "state" : "AL" }
{ "largest_city" : "LITTLE ROCK", "population" : 192895, "state" : "AR" }
{ "largest_city" : "PHOENIX", "population" : 890853, "state" : "AZ" }
{ "largest_city" : "LOS ANGELES", "population" : 2102295, "state" : "CA" }

数组

通过数组中的值聚合文档可能很困难。 请考虑以下人员收藏:

{ "_id" : ObjectId("572d6f1e7651d0f43f521054"), "name" : "susan", "sports" : [ "badminton", "squash" ] }
{ "_id" : ObjectId("572d6f347651d0f43f521055"), "name" : "paul", "sports" : [ "badminton", "squash", "football" ] }
{ "_id" : ObjectId("572d6f4c7651d0f43f521056"), "name" : "jane", "sports" : [ "squash", "baseball" ] }
{ "_id" : ObjectId("572d6f737651d0f43f521057"), "name" : "rick", "sports" : [ "baseball", "tennis", "basketball" ] }

对运动阵列中的值进行聚合是很困难的。 $ unwind操作符分解出这些值:

db.people.aggregate([
{"$unwind" : "$sports"}
])

...这是结果集的样子:

{ "_id" : ObjectId("572d6f1e7651d0f43f521054"), "name" : "susan", "sports" : "badminton" }
{ "_id" : ObjectId("572d6f1e7651d0f43f521054"), "name" : "susan", "sports" : "squash" }
{ "_id" : ObjectId("572d6f347651d0f43f521055"), "name" : "paul", "sports" : "badminton" }
{ "_id" : ObjectId("572d6f347651d0f43f521055"), "name" : "paul", "sports" : "squash" }
{ "_id" : ObjectId("572d6f347651d0f43f521055"), "name" : "paul", "sports" : "football" }
{ "_id" : ObjectId("572d6f4c7651d0f43f521056"), "name" : "jane", "sports" : "squash" }
{ "_id" : ObjectId("572d6f4c7651d0f43f521056"), "name" : "jane", "sports" : "baseball" }
{ "_id" : ObjectId("572d6f737651d0f43f521057"), "name" : "rick", "sports" : "baseball" }
{ "_id" : ObjectId("572d6f737651d0f43f521057"), "name" : "rick", "sports" : "tennis" }
{ "_id" : ObjectId("572d6f737651d0f43f521057"), "name" : "rick", "sports" : "basketball" }

因此,对于每个原始文档,将会有与运动数组中的条目一样多的结果文档。 苏珊现在有2个文件,保罗3等。 现在,我们可以在分组阶段计算每项运动的频率:

db.people.aggregate([
{"$unwind" : "$sports"},
{"$group" : {"_id" : "$sports", "count" : {$sum: 1}}}
])

结果如下:

{ "_id" : "tennis", "count" : 1 }
{ "_id" : "badminton", "count" : 2 }
{ "_id" : "squash", "count" : 3 }
{ "_id" : "football", "count" : 1 }
{ "_id" : "baseball", "count" : 2 }
{ "_id" : "basketball", "count" : 1 }

$ unwind是我们在MongoDb聚合介绍中处理的最后一个聚合运算符。

以下文档页面将描述所有聚合类型和操作符:

  • https://docs.mongodb.com/manual/aggregation/

  • https://docs.mongodb.com/manual/reference/operator/aggregation/

  • SQL到MongoDb聚合映射图

我们再回顾一下另外两个例子。

过滤城市和选定州的平均人口

首先,我们要计算出加州和纽约的人口超过25000人的平均人口。

我们将从匹配阶段开始,我们只想包括CA和NY的地方:

db.zipcodes.aggregate([	
	{$match:
		{
			"state" : {$in : ["CA", "NY"]}
		}
	}
])

接下来我们总结了每个城市的人口:

db.zipcodes.aggregate([	
	{$match:
		{
			"state" : {$in : ["CA", "NY"]}
		}
	},
	{"$group":
		{
			"_id":"$city", 
			"population":{$sum:"$pop"}
		}
	}
])

上述步骤是必要的,因为同一个城市可以有多个邮政编码,所以他们可以在集合中图2或更多次。

下一步又是一个匹配的步骤,我们只想包括人口超过25000的城市:

db.zipcodes.aggregate([	
	{$match:
		{
			"state" : {$in : ["CA", "NY"]}
		}
	},
	{"$group":
		{
			"_id":"$city", 
			"population":{$sum:"$pop"}
		}
	},
	{$match:
		{
			"population" : {$gt : 25000}
		}
	}
])

我们现在可以计算小组阶段的总体平均水平。 我们不想有任何分组ID,我们想要一个单一的数字。 这里的一个小技巧是为_id字段设置一个空值。 我们还将添加一个最后的项目阶段,我们压制null _id字段并输出平均人口:

db.zipcodes.aggregate([	
	{$match:
		{
			"state" : {$in : ["CA", "NY"]}
		}
	},
	{"$group":
		{
			"_id":"$city", 
			"population":{$sum:"$pop"}
		}
	},	
	{$match:
		{
			"population" : {$gt : 25000}
		}
	},
	{$group:
		{
			"_id" : null,
			"pop" : {$avg: "$population"}
		}
	},
	{$project:
		{
			"_id" : 0,
			"average_population" : "$pop"
		}	
	}
])

这是响应:

{ "average_population" : 83199.93478260869 }

计算A,B,C等城市总人口

我们要计算名字以A,B或C开头的城市的平均人口。这是完整的查询:

db.zipcodes.aggregate([
	{$project:
		{
			"city" : "$city",
			"population" : "$pop",
			"first_char": {$substr : ["$city",0,1]},
		}
	},
	{$match:
		{
			"first_char" : {$in : ["A", "B", "C"]}
		}
	},
	{$group:
		{
			"_id" : null,
			"sum_population" : {$sum: "$population"}
		}
	}
])

$ substr运算符是新的。 它从源字符串中提取一个子字符串。 在这种情况下,我们对每个城市名称的第一个字符感兴趣。 然后,我们使用$ in运算符仅包括first_char属性为A,B或C的文档。最后,我们计算其总体数。 答案是55582457。

在下一篇文章中,我们将介绍如何在.NET驱动程序中编写聚合。


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CsharpMongo/26.html