如何查询mongo集合以返回包含子文档中包含计算值的虚拟字段的完整文档?

时间:2014-07-24 01:39:02

标签: mongodb mongodb-query aggregation-framework

我试图查询包含子文档的特定文档的集合。子文档包含我想要获取的值 来自该子文档的最高和最低分数,并将该结果作为虚拟字段返回到原始文档。

我有以下数据集:

{
"_id" : "d0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e",
"name" : "Addison Hunt",
"tests" : [
    {
        "name"  : "lorem",
        "score" : 79
    },
    {
        "name"  : "vallum",
        "score" : 100
    },
    {
        "name"  : "ipsum",
        "score" : 65
    }
],
"created_at" : 1401488865684,
"class" : "dolor sit amit",
"user_id" : "005G5635231325O4VIAU"

}

在mongo 2.4中,如何查询mongo一次返回以下结果:

{
    "_id" : "d0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e",
    "name" : "Addison Hunt",
    "tests" : [
        {
            "name"  : "lorem",
            "score" : 79
        },
        {
            "name"  : "vallum",
            "score" : 100
        },
        {
            "name"  : "ipsum",
            "score" : 65
        }
    ],
    "created_at" : 1401488865684,
    "class" : "dolor sit amit",
    "user_id" : "005G5635231325O4VIAU",
    "worst_test": {
        "name"  : "ipsum",
        "score" : 65
    },
    "best_test": {
        "name"  : "vallum",
        "score" : 100
    }
}

哪里" best_test"和" worst_test"是分别代表具有最高和最低分数的测试的虚拟字段。 我尝试过很多不同的方法,而我最接近的就是这个问题:

db.students.aggregate([
    { $match: { 
        '_id': 'd0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e'
    }},
    { $unwind: '$tests' },
    { $sort: {'tests.score': 1} },
    { $group: { 
        _id: '$_id',
        student_tests: {$push: "$$ROOT"},
        worst_test: {$first: '$tests'},
        best_test: { $last: '$tests' } 
    }}
]);

产生这个结果:

{
"_id" : "d0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e",
"student_tests" : [
    {
        "name" : "Addison Hunt",
        "tests" : [
            {
                "name"  : "ipsum",
                "score" : 65
            }
        ],
        "created_at" : 1401488865684,
        "class" : "dolor sit amit",
        "user_id" : "005G5635231325O4VIAU",
    },
    {
        "name" : "Addison Hunt",
        "tests" : [
            {
                "name"  : "lorem",
                "score" : 79
            }
        ],
        "created_at" : 1401488865684,
        "class" : "dolor sit amit",
        "user_id" : "005G5635231325O4VIAU",
    },
    {
        "name" : "Addison Hunt",
        "tests" : [
            {
                "name"  : "vallum",
                "score" : 100
            }
        ],
        "created_at" : 1401488865684,
        "class" : "dolor sit amit",
        "user_id" : "005G5635231325O4VIAU",
    },
],
"worst_test": {
    "name"  : "ipsum",
    "score" : 65
},
"best_test": {
    "name"  : "vallum",
    "score" : 100
}

}

1 个答案:

答案 0 :(得分:2)

如果您使用$$ROOT,那么实际上您使用的是MongoDB 2.6,因为这是仅在该版本中引入的聚合变量。

但是,虽然对于各种各样的事情很方便,但它所做的只是代表管道现阶段使用的整个文档。要执行您想要的操作并返回未修改的原始文档但包含其他字段,您可以在$project阶段使用该文档,然后$unwind分配到_id字段,但实际上您没有&# 39;为了从这些元素中获取正确的文档形状,完全相同的文档在最后仍然需要$project

您最好的选择是投影字段,但在应用任何$sort之前保留数组未经修改的副本:

db.students.aggregate([
    { "$match": { 
        "_id": "d0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e"
    }},
    { "$project": {
         "name": 1,
         "tests": 1,
         "created_at": 1,
         "class": 1,
         "user_id": 1,
         "testCopy": "$tests" 
    }},
    { "$unwind": "$testCopy" },
    { "$sort": { "testCopy.score": 1 } },
    { "$group": { 
        "_id: "$_id",
        "tests": { "$first": "$tests" },
        "created_at": { "$first": "$created_at" },
        "class": { "$first": "$class" },
        "user_id": { "$first": "$user_id" },
        "worst_test": { "$first": "$testCopy" },
        "best_test": { "$last": "$testCopy" } 
    }}
]);

或者如上所述使用$$ROOT,或者只是将_id下的字段单独放在$project中:

db.students.aggregate([
    { "$match": { 
        "_id": "d0e78492342f9f-f843ec7-4bd14g3h-bh34j3a9-02d6ah32k8e6b79e"
    }},
    { "$project": {
        "_id": "$$ROOT",
        "tests": 1
    }},
    { "$unwind": "$tests" },
    { "$sort": { "tests.score": 1 } },
    { "$group": { 
        "_id": "$_id",
        "aworst_test": { "$first": "$tests" },
        "abest_test": { "$last": "$tests" } 
    }},
    { "$project": {
        "_id": "$_id._id",
        "tests": "$_id.tests",
        "created_at": "$_id.created_at",
        "class": "$_id.class",
        "user_id": "$_id.user_id",
        "worst_test": "$aworst_test",
        "best_test": "$abest_test"
    }}
]);

但是如您所见,您仍在某处进行$project工作,以获得您想要的结构,以及"重命名的字段"保持您想要的字段顺序,否则$project将优化"并且"保持"任何尚未重命名的字段和"追加"现有的新领域。

确实没有简单的方法来获得所有领域"就像你最初发现它们一样。像$project$group这样的操作是"全有或全无"事情,他们只明确地产生你告诉他们的东西。