mongoDB: how to reverse $unwind

a 夏天 提交于 2019-12-05 11:52:18

There is a particular trick to how this is handled, but firstly if you have MongoDB 2.6 or greater available then you can actually do what you want without using $unwind. This can be very handy for performance if you are processing a lot of documents.

The key operators here are $map which processes arrays in place and the $allElementsTrue operator which will evaluate your "result" fields. The usage of "map" here allows both the testing of the inner "tests" array to see where the "result" fields in there all meet the true condition. In the outer array case, this "result" can be placed into those documents as you require, and of course the full evaluation for the document follows the same rules:

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"
                 }
            }
        }
    }}
])

The way to do this in earlier versions requires you to $group back in two steps in order to "rebuild" the arrays while doing the tests on those "result" fields again. The other difference here is also using the $min operator as false will be considered a lesser value than true and evaluates to the same "allElements" concept:

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"
            }
        }
    }}
])
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!