使用聚合框架使用 MongoDB 进行组计数
Posted
技术标签:
【中文标题】使用聚合框架使用 MongoDB 进行组计数【英文标题】:Group count with MongoDB using aggregation framework 【发布时间】:2012-10-25 18:10:07 【问题描述】:假设我的 MongoDB 架构如下所示:
car_id: "...", owner_id: "..."
这是一个多对多的关系。例如,数据可能如下所示:
+-----+----------+--------+
| _id | owner_id | car_id |
+-----+----------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 3 | 4 |
| 7 | 3 | 5 |
| 8 | 3 | 6 |
| 9 | 3 | 7 |
| 10 | 1 | 1 | <-- not unique
+-----+----------+--------+
我想获取每个车主拥有的汽车数量。在 SQL 中,这可能看起来像:
SELECT owner_id, COUNT(*) AS cars_owned
FROM (SELECT owner_id FROM car_owners GROUP BY owner_id, car_id) AS t
GROUP BY owner_id;
在这种情况下,结果如下所示:
+----------+------------+
| owner_id | cars_owned |
+----------+------------+
| 1 | 3 |
| 2 | 2 |
| 3 | 4 |
+----------+------------+
我怎样才能通过聚合框架使用 MongoDB 完成同样的事情?
【问题讨论】:
@JohnnyHK,我认为我列出我尝试完成此任务的 10 种不同方法不会帮助您或其他任何人更有效地回答这个问题,因为它们不起作用。我已经做了一些工作来准确解释我正在尝试做什么,以及我可能在 SQL 中采用的方法。我查看了上下 MongoDB 文档,但我的管道聚合方法都没有奏效,可能是因为我对使用聚合框架还是新手。 在您的架构中,每个文档是否只有一辆汽车(由 id 表示)?在这种情况下,要查找所有者拥有的汽车数量,您不只是在查找集合中有多少文档具有该 owner_id 吗?在这种情况下,您可以执行类似 db.foo.find( owner_id : [owner id here] ).count() 的操作来获取集合中具有该 owner_id 的文档数。 您现有的代码不起作用完全没问题,但是通过发布它我们可以看到您采取的方向以及您可能缺少的概念。 @Louisa,这是一个多对多的关系。可以有很多车和很多车主。 可以有多个文档具有相同的owner_id
/car_id
对吗?例如owner_id = 1
和 car_id = 1
? 的两个文档?
【参考方案1】:
$group
类似于 SQL Group by command。在下面的示例中,我们将根据公司成立的年份汇总公司。并计算每家公司的平均员工人数。
db.companies.aggregate([
$group:
_id:
founded_year: "$founded_year"
,
average_number_of_employees:
$avg: "$number_of_employees"
,
$sort:
average_number_of_employees: -1
])
这个聚合管道有 2 个阶段
$group
$sort
现在,$group
阶段的基础是我们指定为文档一部分的_id
字段。这就是$group
运算符本身的值,它使用对arrogation 框架语法的非常严格的解释。 _id
是我们如何定义、如何控制、如何调整小组赛阶段用来组织它看到的文档的方式。
以下查询使用$sum
运算符查找人员与公司的关系:
db.companies.aggregate([
$match:
"relationships.person":
$ne: null
,
$project:
relationships: 1,
_id: 0
,
$unwind: "$relationships"
,
$group:
_id: "$relationships.person",
count:
$sum: 1
,
$sort:
count: -1
])
【讨论】:
这些截图怎么了?【参考方案2】:为了适应潜在的重复,您需要使用两个$group
操作:
db.test.aggregate([
$group:
_id: owner_id: '$owner_id', car_id: '$car_id'
,
$group:
_id: '$_id.owner_id',
cars_owned: $sum: 1
,
$project:
_id: 0,
owner_id: '$_id',
cars_owned: 1
]
, function(err, result)
console.log(result);
);
给出格式如下的结果:
[ cars_owned: 2, owner_id: 10 ,
cars_owned: 1, owner_id: 11 ]
【讨论】:
很好的答案。我真的很亲近。我有 2 个流水线组,但我向$sum
运算符提供了一个字段名称而不是 1。这解决了它。谢谢!
如何将输出限制为仅拥有多于一辆车 (cars_owned > 1) 的人?
@IngviGautsson $sort : "cars_owned" : -1, $limit : 10
在$project
之后和]
之前添加
天哪,sql这么简单,把sql带回来!以上是关于使用聚合框架使用 MongoDB 进行组计数的主要内容,如果未能解决你的问题,请参考以下文章