24

調査とカテゴリ 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
}
>
4

1 に答える 1

34

aggregate() への引数の操作がパイプラインを形成することを理解することが重要です。これは、パイプラインの任意の要素への入力が、パイプラインの前の要素によって生成されたドキュメントのストリームであることを意味していました。

あなたの例では、最初のクエリは次のようなドキュメントのパイプラインを作成します。

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

これは、パイプラインの 2 番目の要素が、キーが「_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
 }
于 2012-06-15T17:42:44.723 に答える