【问题标题】:Multiple group operations using Mongo aggregation framework使用 Mongodb 聚合框架的多组操作
【发布时间】:2012-06-14 20:11:51
【问题描述】:

给定一组关联调查和类别 ID 的问题:

> db.questions.find().toArray();
[
    {
        "_id" : ObjectId("4fda05bc322b1c95b531ac25"),
        "id" : 1,
        "name" : "Question 1",
        "category_id" : 1,
        "survey_id" : 1,
        "score" : 5
    },
    {
        "_id" : ObjectId("4fda05cb322b1c95b531ac26"),
        "id" : 2,
        "name" : "Question 2",
        "category_id" : 1,
        "survey_id" : 1,
        "score" : 3
    },
    {
        "_id" : ObjectId("4fda05d9322b1c95b531ac27"),
        "id" : 3,
        "name" : "Question 3",
        "category_id" : 2,
        "survey_id" : 1,
        "score" : 4
    },
    {
        "_id" : ObjectId("4fda4287322b1c95b531ac28"),
        "id" : 4,
        "name" : "Question 4",
        "category_id" : 2,
        "survey_id" : 1,
        "score" : 7
    }
]

我可以通过以下方式找到类别平均值:

db.questions.aggregate(
    { $group : {
        _id : "$category_id",
        avg_score : { $avg : "$score" }
    }
}
);

{
    "result" : [
        {
            "_id" : 1,
            "avg_score" : 4
        },
        {
            "_id" : 2,
            "avg_score" : 5.5
        }
    ],
    "ok" : 1
}

如何获得类别平均值的平均值(注意这与简单地对所有问题进行平均不同)?我会假设我会进行多个小组操作,但这会失败:

> db.questions.aggregate(
...   { $group : {
...     _id : "$category_id",
...     avg_score : { $avg : "$score" },
...   }},
...   { $group : {
...     _id : "$survey_id",
...     avg_score : { $avg : "$score" },
...   }}
... );
{
    "errmsg" : "exception: the _id field for a group must not be undefined",
    "code" : 15956,
    "ok" : 0
}
>

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    了解聚合()参数中的操作形成了一个管道,这一点很重要。这意味着管道中任何元素的输入都是管道中前一个元素生成的文档流。

    在您的示例中,您的第一个查询会创建一个如下所示的文档管道:

    {
        "_id" : 2,
        "avg_score" : 5.5
    },
    {
        "_id" : 1,
        "avg_score" : 4
    }
    

    这意味着管道的第二个元素正在查看一系列文档,其中唯一的键是“_id”和“avg_score”。此文档流中不再存在键“category_id”和“score”。

    如果您想在此流上进一步聚合,则必须使用在管道中此阶段看到的键进行聚合。由于您想要平均平均值,因此您需要为 _id 字段输入一个常量值,以便将所有输入文档分组为一个结果。

    以下代码产生正确的结果:

    db.questions.aggregate(
        { $group : {
            _id : "$category_id",
            avg_score : { $avg : "$score" },
            }
        },
        { $group : {
            _id : "all",
            avg_score : { $avg : "$avg_score" },
            }
        }
    );
    

    运行时会产生以下输出:

     {
        "result" : [
            {
            "_id" : "all",
            "avg_score" : 4.75
            }
        ],
        "ok" : 1
     }
    

    【讨论】:

    • 嗯,不知道你可以使用常量。我认为这种方法不适用于更高级别的分组。谢谢,看起来它适用于这个用例
    • 如果您想在更高级别进行分组,您只需要确保相关键被管道的第一个元素投影到文档流中。如果您有具体示例,请随时发布另一个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多