考虑以下测试结果集合:

[{
    _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 2.6或更高版本,则实际上可以执行所需的操作而无需使用 $unwind 。如果要处理大量文档,这对性能非常方便。

此处的关键运算符是 $map $allElementsTrue 运算符,这些运算符将处理适当的数组, $group 运算符将评估您的“结果”字段。此处使用“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"
                 }
            }
        }
    }}
])

在早期版本中执行此操作的方法要求您分两步返回 $min ,以便在重新对那些“结果”字段进行测试时“重建”阵列。这里的另一个区别是使用了ojit_a运算符,因为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"
            }
        }
    }}
])

关于mongoDB:如何撤消$ unwind,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25136536/

10-11 07:32