2

假设我有这样的文件:

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

我想计算集合中的答案记录数。显然,该文档提供了两个答案记录,即“1”和“3”。所以,我的问题是如何使用聚合管道来实现这一点。

4

2 回答 2

1

在你的情况下,只使用 JS 要容易得多。

在 mongo 外壳上:

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

Object.keys(json).length;

打印 2 表示该文档中的答案记录数。

于 2016-10-03T15:31:24.813 回答
1

对于 MongoDB 3.6 和更高版本,使用$objectToArray聚合管道中的运算符将文档转换为数组。返回数组包含原始文档中每个字段/值对的元素。返回数组中的每个元素都是一个包含两个字段k和的文档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" }
    ]
}

然后您可以简单地应用聚合的$project管道,该管道使用$size运算符返回每个文档的 answer_records 数组的长度:

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 回答