2

次のようなドキュメントがあるとします。

{
"_id" : ObjectId("57eb386e37b4842ff5f386c9"),
"lesson_id" : ObjectId("57e27cd190e6993e393f5c74"),
"student_id" : ObjectId("57d3c3f590e6995fe8de7932"),
"answer_records" : {
    "1" : {
        "answer" : [ 
            "A"
        ]
    },
    "3" : {
        "answer" : [ 
            "C"
        ]
    }
}

コレクション内の回答レコードの数をカウントしたい。どうやら、このドキュメントは "1" と "3" の 2 つの回答レコードを提供しています。だから、私の質問は、集約パイプラインを使用してこれを達成する方法です。

4

2 に答える 2

1

あなたの場合、JS を使用する方がはるかに簡単です。

モンゴシェルで:

var json=db.sof.findOne().answer_records;

Object.keys(json).length;

当該文書の回答件数は 2 を出力します。

于 2016-10-03T15:31:24.813 に答える
1

MongoDB 3.6 以降では$objectToArray、集計パイプライン内で演算子を使用して、ドキュメントを配列に変換します。返される配列には、元のドキュメントの各フィールド/値のペアの要素が含まれています。k返される配列の各要素は、 と の 2 つのフィールドを含むドキュメントですv

配列を取得したら、$addFieldsパイプライン ステップを使用して、カウントを保持するフィールドを作成できます。実際のカウントは、$size演算子を使用して導出されます。

これはすべて、次のように式をネストすることにより、単一のパイプラインで実行できます。

db.collection.aggregate([
    {
        "$addFields": {
            "answers_count": {
                "$size": { 
                    "$objectToArray": "$answer_records"
                }
            }
        }
    }     
])

サンプル出力

{
    "_id" : ObjectId("57eb386e37b4842ff5f386c9"),
    "lesson_id" : ObjectId("57e27cd190e6993e393f5c74"),
    "student_id" : ObjectId("57d3c3f590e6995fe8de7932"),
    "answer_records" : {
        "1" : {
            "answer" : [ 
                "A"
            ]
        },
        "3" : {
            "answer" : [ 
                "C"
            ]
        }
    },
    "answers_count": 2
}

上記の演算子をサポートしていない MongoDB サーバー バージョンの場合、集約フレームワークで効率的なクエリを実行するには、スキーマの設計を変更する必要があります。現在のところ、JavaScript を使用してクライアントまたはサーバーでドキュメントを前処理する必要があるため、クエリを高速化するために構築された MongoDB の優れたインフラストラクチャを十分に活用することはできません。

理想的な設計は次のとおりです。

{
    "_id" : ObjectId("57eb386e37b4842ff5f386c9"),
    "lesson_id" : ObjectId("57e27cd190e6993e393f5c74"),
    "student_id" : ObjectId("57d3c3f590e6995fe8de7932"),
    "answer_records" : [
        { "id": "1", "answer": "A" }
        { "id": "3", "answer": "C" }
    ]
}

次に、演算子を使用してドキュメントごとの answer_records 配列の長さを返す集計の$projectパイプラインを適用するだけです。$size

db.collection.aggregate([
    { 
        "$project": {
            "lesson_id": 1,
            "student_id": 1,
            "count": { "$size": "$answer_records" }
        }
    }
])

コレクション全体のアンサー レコードの総数が必要な場合は、別の$groupパイプラインを追加して、null の _id を使用してすべてのドキュメントの累積合計を取得します。

db.collection.aggregate([
    { 
        "$project": {           
            "count": { "$size": "$answer_records" }
        }
    },
    {
        "$group": {
            "_id": null,
            "total_answers": { "$sum": "$count" }
        }
    }
])

それ以外の場合、現在の設計では、唯一のオプションは MapReduce であり、これははるかに低速です。

db.collection.mapReduce(
    function() {
        emit(this._id, Object.keys(this.answer_records).length);
    },
    function() { },
    { "out": { "inline": 1 } }
)

サンプル出力:

{
    "results" : [ 
        {
            "_id" : ObjectId("57eb386e37b4842ff5f386c9"),
            "value" : 2
        }
    ],
    ....
}

コレクション内のすべてのドキュメントの合計を取得するには、次の mapReduce 操作を実行します。

db.collection.mapReduce(
    function() {
        emit(null, Object.keys(this.answer_records).length);
    },
    function(key, values) {
        return Array.sum(values);
    },
    { "out": { "inline": 1 } }
)
于 2016-10-03T07:36:49.400 に答える