对聚合中字段的最大值进行分组

时间:2017-04-10 12:41:03

标签: mongodb mongodb-query aggregation-framework

我们说我有2个字段AB。字段A可以采用以下值:[a,b,c,d,e]和B:[x,y]

我正在寻找一个MongoDB聚合管道查询:

  1. 计算A中每个值出现在我的数据库中的次数
  2. 显示最B
  3. A的值的分布

    示例:

    让我们说' c'恰好是A的最大值:

    输出结果为:

    { '_id': { 'A': 'c', 'B': 'x' }, 'count': 43 }
    { '_id': { 'A': 'c', 'B': 'y' }, 'count': 13 }
    

    我设法做到这一点的唯一方法是将A:c硬编码到我的"$match"语句中。

1 个答案:

答案 0 :(得分:1)

您可以从输出中推断出聚合管道。 _id字段有两个键AB,表示 $group 键由两个键组成,并且计数是通过调用 $sum 累加器。

填充测试集

假设我们使用以下文档生成测试集合

db.collection.insert([
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "e", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "a", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "a", "B": "x" },
    { "A": "c", "B": "y" },
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "b", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "c", "B": "x" },
    { "A": "a", "B": "y" },
    { "A": "a", "B": "y" },
    { "A": "b", "B": "y" },
    { "A": "b", "B": "y" },
    { "A": "b", "B": "y" },
    { "A": "b", "B": "y" },
    { "A": "b", "B": "y" },
    { "A": "c", "B": "y" },
    { "A": "e", "B": "y" },
    { "A": "e", "B": "y" },
    { "A": "d", "B": "y" },
    { "A": "d", "B": "y" },
    { "A": "d", "B": "y" }
])

然后,以下初始管道将对这两个键上的文档进行分组并获取计数:

db.collection.aggregate([
    {
        "$group": {
            "_id": { "A": "$A", "B": "$B" },
            "count": { "$sum": 1 }
        }
    }
])

示例输出

/* 1 */
{
    "_id" : {
        "A" : "e",
        "B" : "y"
    },
    "count" : 2
}

/* 2 */
{
    "_id" : {
        "A" : "c",
        "B" : "x"
    },
    "count" : 11
}

/* 3 */
{
    "_id" : {
        "A" : "b",
        "B" : "y"
    },
    "count" : 5
}

/* 4 */
{
    "_id" : {
        "A" : "b",
        "B" : "x"
    },
    "count" : 1
}

/* 5 */
{
    "_id" : {
        "A" : "e",
        "B" : "x"
    },
    "count" : 1
}

/* 6 */
{
    "_id" : {
        "A" : "d",
        "B" : "y"
    },
    "count" : 3
}

/* 7 */
{
    "_id" : {
        "A" : "a",
        "B" : "y"
    },
    "count" : 2
}

/* 8 */
{
    "_id" : {
        "A" : "a",
        "B" : "x"
    },
    "count" : 2
}

/* 9 */
{
    "_id" : {
        "A" : "c",
        "B" : "y"
    },
    "count" : 2
}

从观察来看,具有计数11的文档#2具有" c"作为最有价值的值:

/* 2 */
{
    "_id" : {
        "A" : "c",
        "B" : "x"
    },
    "count" : 11
}

到目前为止,您可以进一步聚合以获得最重要的密钥。您需要另一个 $group 管道,它将通过A键对上一个管道的结果进行分组,创建一个包含文档详细信息的列表,即 计数和具有该计数的相应B值。您还需要每组A值的计数字段:

db.collection.aggregate([
    {
        "$group": {
            "_id": { "A": "$A", "B": "$B" },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.A",
            "counts": {
                "$push": {
                    "B": "$_id.B",
                    "count": "$count"
                }
            },
            "count": { "$sum": "$count" } 
        }
    }
])

示例输出

/* 1 */
{
    "_id" : "e",
    "counts" : [ 
        {
            "B" : "y",
            "count" : 2
        }, 
        {
            "B" : "x",
            "count" : 1
        }
    ],
    "count" : 3
}

/* 2 */
{
    "_id" : "c",
    "counts" : [ 
        {
            "B" : "x",
            "count" : 11
        }, 
        {
            "B" : "y",
            "count" : 2
        }
    ],
    "count" : 13
}

/* 3 */
{
    "_id" : "b",
    "counts" : [ 
        {
            "B" : "y",
            "count" : 5
        }, 
        {
            "B" : "x",
            "count" : 1
        }
    ],
    "count" : 6
}

/* 4 */
{
    "_id" : "d",
    "counts" : [ 
        {
            "B" : "y",
            "count" : 3
        }
    ],
    "count" : 3
}

/* 5 */
{
    "_id" : "a",
    "counts" : [ 
        {
            "B" : "y",
            "count" : 2
        }, 
        {
            "B" : "x",
            "count" : 2
        }
    ],
    "count" : 4
}

在此阶段,您只需要对计数字段中的文档进行排序,并在按降序排列文档时返回顶部文档:

db.collection.aggregate([
    {
        "$group": {
            "_id": { "A": "$A", "B": "$B" },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.A",
            "counts": {
                "$push": {
                    "B": "$_id.B",
                    "count": "$count"
                }
            },
            "count": { "$sum": "$count" }
        }
    },
    { "$sort": { "count": -1 } },
    { "$limit": 1 }
])

产生:

{
    "_id" : "c",
    "counts" : [ 
        {
            "B" : "x",
            "count" : 11
        }, 
        {
            "B" : "y",
            "count" : 2
        }
    ],
    "count": 13
}

虽然输出与所需的结构不同,但仍能充分解决问题

1。计算A中每个值出现在我的数据库中的次数 - >所需的管道:

db.collection.aggregate([
    {
        "$group": {
            "_id": { "A": "$A", "B": "$B" },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.A",                
            "count": { "$sum": "$count" }
        }
    }
])

2。显示B的最新值A的分布

db.collection.aggregate([
    {
        "$group": {
            "_id": { "A": "$A", "B": "$B" },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": "$_id.A",
            "counts": {
                "$push": {
                    "B": "$_id.B",
                    "count": "$count"
                }
            },
            "count": { "$sum": "$count" }
        }
    },
    { "$sort": { "count": -1 } },
    { "$limit": 1 }
])