首页 文章

mongoDB:如何逆转$ unwind

提问于
浏览
4

考虑一下这组测试结果:

[{
    _id: ObjectId(...),
    name: "Test1",
    acts: [
    {
        name: "act1", 
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: true}]
    }]
},
{
    _id: ObjectId(...),
    name: "Test2",
    acts: [
    {
        name: "act1", 
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: false}]
    }, 
    {
        name: "act2", 
        tests: [
            {name: "test3", result: true}]
    }]
}]

我正在尝试使用聚合来创建一个计算字段,其中包含所有测试结果的总和,我想要这样的东西:

[{
    _id: ObjectId(...),
    name: "Test1",
    result: true, //new aggregated value
    acts: [
    {
        name: "act1", 
        result: true, //new aggregated value
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: true}]
    }]
},
{
    _id: ObjectId(...),
    name: "Test2",
    result: false, //new aggregated value
    acts: [
    {
        name: "act1", 
        result: false, //new aggregated value
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: false}]
    }, 
    {
        name: "act2", 
        result: true, //new aggregated value
        tests: [
            {name: "test3", result: true}]
    }]
}]

我尝试过使用aggregate和$ unwind,$ project和$ group:

aggregate([
  {$unwind: "$acts"},
  {$unwind: "$acts.tests"},
  {$project: {name: 1, acts: 1, failed: {$cond: {if: {$eq: ["$acts.tests.test", "true" ]}, then: 0, else: 1}}}},
  {$group: {_id: "$_id", failedCount: {$sum: "$failed"}, acts: {$push: "$acts.tests"}}}
])

但我不能让它反转$ unwind操作,我只得到结果数据结构与原始数据结构不同 . 是否可以使结果看起来与原始集合完全相同但具有新的聚合值?

/ gemigspam

1 回答

  • 12

    如何处理这个问题有一个特殊的技巧,但首先如果你有MongoDB 2.6或更高版本,那么你可以实际做你想做的事情而不用$unwind . 如果您要处理大量文档,这对于性能非常方便 .

    这里的关键操作符是$map,它处理数组到位,$allElementsTrue运算符将评估你的"result"字段 . 这里使用"map"允许测试内部"tests"数组,以查看其中"result"字段的所有字符都满足真实条件 . 在外部数组的情况下,可以根据需要将"result"放入这些文档中,当然,对文档的完整评估遵循相同的规则:

    db.test.aggregate([
        { "$project": {
            "name": 1,
            "result": {
                "$allElementsTrue": {
                    "$map": {
                        "input": "$acts",
                        "as": "act",
                        "in": {
                            "$allElementsTrue": {
                                "$map": {
                                     "input": "$$act.tests",
                                     "as": "test",
                                     "in": "$$test.result"
                                }
                            }
                        }
                    }
                }
            },
            "acts": {
                "$map": {
                     "input": "$acts",
                     "as": "act",
                     "in": {
                        "name": "$$act.name",
                        "result": {
                            "$allElementsTrue": {
                                "$map": {
                                    "input": "$$act.tests",
                                    "as": "test",
                                    "in": "$$test.result"
                                }
                            }
                        },
                        "tests": "$$act.tests"
                     }
                }
            }
        }}
    ])
    

    在早期版本中执行此操作的方法要求您在两个步骤中返回$group,以便在再次对这些"result"字段进行测试时_1192461_数组 . 这里的另一个区别也是使用$min运算符,因为 false 将被视为比 true 更小的值并且计算为相同的"allElements"概念:

    db.test.aggregate([
        { "$unwind": "$acts" },
        { "$unwind": "$acts.tests" },
        { "$group": {
            "_id": {
                "_id": "$_id",
                "name": "$name",
                "actName": "$acts.name"
            },
            "result": { "$min": "$acts.tests.result" },
            "tests": {
               "$push": {
                   "name": "$acts.tests.name",
                   "result": "$acts.tests.result"
               }
            }
        }},
        { "$group": {
            "_id": "$_id._id",
            "name": { "$first": "$_id.name" },
            "result": { "$min": "$result" },
            "acts": {
                "$push": {
                    "name": "$_id.actName",
                    "result": "$result",
                    "tests": "$tests"
                }
            }
        }}
    ])
    

相关问题