【问题标题】:Group count with MongoDB using aggregation framework使用聚合框架使用 MongoDB 进行组计数
【发布时间】: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 = 1car_id = 1? 的两个文档?

标签: mongodb aggregation-framework


【解决方案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 个阶段

  1. $group
  2. $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带回来!
猜你喜欢
  • 2018-01-16
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
  • 2016-12-21
  • 2013-07-31
  • 1970-01-01
  • 2019-02-01
  • 2018-10-28
相关资源
最近更新 更多