MongoDB按组计数查询

339

我正在尝试使用MongoDB玩耍,试图弄清如何进行简单的

SELECT province, COUNT(*) FROM contest GROUP BY province

但是我似乎无法使用聚合函数解决它。我可以使用一些非常奇怪的组语法来做到这一点。

db.user.group({
    "key": {
        "province": true
    },
    "initial": {
        "count": 0
    },
    "reduce": function(obj, prev) {
        if (true != null) if (true instanceof Array) prev.count += true.length;
        else prev.count++;
    }
});

但是是否有使用聚合函数更简单/更快的方法呢?

9个回答

541

使用aggregate是更简单的实现方式:

db.contest.aggregate([
    {"$group" : {_id:"$province", count:{$sum:1}}}
])

1
当我尝试使用 "errmsg" : "exception: A pipeline stage specification object must contain exactly one field.", 时,我会收到一个错误消息。 - Steven
你如何对其进行分组排序?我想按-1排序计数。 - Filip Bartuzi
7
在文档页面里有一个例子,你需要向管道中添加一个排序操作,如 { $sort: { count: -1 } } - elaich
1
我遇到了与@Steven相同的异常,原因是我只复制粘贴了第二行并省略了周围的方括号。 - Peter Perháč
@Steven,你需要正确地执行它,使用类似这样的语句:.aggregate(aggregate).exec(); - BivorAdrito
这些查询中,$非常重要。 - Akaisteph7

164

基于聚合函数结果,我需要进行一些额外的操作。最终我在MongoDB中找到了一些与聚合函数结果相关的解决方案。我有一个名为Request的集合,其中包含字段request,source,status,requestDate

单字段分组&统计:

db.Request.aggregate([
    {"$group" : {_id:"$source", count:{$sum:1}}}
])

多字段分组并计数:

db.Request.aggregate([
    {"$group" : {_id:{source:"$source",status:"$status"}, count:{$sum:1}}}
])

按字段分组、计数和排序:

db.Request.aggregate([
    {"$group" : {_id:{source:"$source",status:"$status"}, count:{$sum:1}}},
    {$sort:{"_id.source":1}}
])

按多个字段分组并使用计数进行排序:

db.Request.aggregate([
    {"$group" : {_id:{source:"$source",status:"$status"}, count:{$sum:1}}},
    {$sort:{"count":-1}}
])

你能解释一下 {_id:{source:"$source",status:"$status"} 这个吗? - Hridoy_089
1
基本上,“_id”字段是每个文档的唯一标识符。该字段接受一个表达式。您可以通过基于分组标准组合多个字段来定义字段的值。有关该字段的更多详细信息,请参见以下链接: https://docs.mongodb.com/manual/reference/operator/aggregation/group/#pipe._S_group - csharpbd

73

如果你需要按多列进行分组,请参照这个模型。在这里,我正在通过 statustype 进行计数:

  db.BusinessProcess.aggregate({
    "$group": {
        _id: {
            status: "$status",
            type: "$type"
        },
        count: {
            $sum: 1
        }
    }
   })

3
_id代表封装多个字段的默认参数? - EugenSunic
@RoyiNamir,请查看此链接。您可能会在那里找到您需要的信息。https://docs.mongodb.com/manual/reference/operator/aggregation/group/#pipe._S_group - csharpbd

54

4
在这里值得注意的是,$sortByCount 实际上是一个“伪操作符”,就像 MongoDB 3.4 引入的其他一些聚合阶段操作符一样。它们真正做的只是 展开 成它们各自的聚合阶段。在这种情况下,就像现有答案中显示的那样,展开成了 $group$sum: 1,以及额外的 $sort 阶段。它们除了让您少打几个字符以外,没有任何优势,这可能会使代码更具描述性(如果您喜欢这种方式)。在我看来,代码中独立的 $group$sort 阶段更具描述性,而且更加灵活。 - Neil Lunn

27

此外,如果您需要限制分组,可以使用:

db.events.aggregate( 
    {$match: {province: "ON"}},
    {$group: {_id: "$date", number: {$sum: 1}}}  
)

10

6

从Mongo 5.0开始,我们还可以使用{ $count: { } }作为{ $sum : 1 }的别名。

// { "province" : "Champagne-Ardenne" }
// { "province" : "Champagne-Ardenne" }
// { "province" : "Haute-Normandie"   }
db.collection.aggregate([
  { $group: { _id: "$province", count: { $count: {} } } }
])
// { "_id" : "Champagne-Ardenne", "count" : 2 }
// { "_id" : "Haute-Normandie",   "count" : 1 }

5
    db.contest.aggregate([
        { $match:{.....May be some match criteria...}},
        { $project: {"province":1,_id:0}},
        { $sortByCount: "$province" }
    ],{allowDiskUse:true});

MongoDB在内存中的排序操作有32MB的限制,当您面向数百万数据公开此查询时,请使用allowDiskUse: true选项,在磁盘级别而不是在内存中进行排序。MongoDB聚合管道有100MB的限制,因此请使用$project来减少流向下一个管道的数据。

如果您使用的是小型数据,则无需使用allowDiskUse选项。


-1

适用于我的Mongo shell命令:

db.getCollection(<collection_name>).aggregate([{"$match": {'<key>': '<value to match>'}}, {"$group": {'_id': {'<group_by_attribute>': "$group_by_attribute"}}}])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接