【问题标题】:mongoDB: how to reverse $unwindmongoDB:如何反转 $unwind
【发布时间】:2014-09-27 23:32:21
【问题描述】:

考虑一下这个测试结果集合:

[{
    _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}]
    }]
}]

我尝试过使用聚合和 $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

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    对此有一个特殊的处理技巧,但首先,如果您有 MongoDB 2.6 或更高版本可用,那么您实际上可以在不使用 $unwind 的情况下做您想做的事情。如果您要处理大量文档,这对于性能来说非常方便。

    这里的关键操作符是 $map 处理数组和 $allElementsTrue 操作符将评估您的“结果”字段。此处“map”的使用允许对内部“tests”数组进行测试,以查看其中的“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,以便在再次对这些“结果”字段进行测试时“重建”数组。这里的另一个区别也是使用$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"
                }
            }
        }}
    ])
    

    【讨论】:

    • 我发现 $group 运算符在这种情况下更有价值,因为它具有灵活性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 2019-05-30
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    相关资源
    最近更新 更多