mongoDB:如何撤消$ unwind [英] mongoDB: how to reverse $unwind

查看:241
本文介绍了mongoDB:如何撤消$ unwind的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下测试结果集合:

Consider this collection of test results:

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

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

I'm trying to use aggregations to create a calculated field with the sum of all test results, I want something like this:

[{
    _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:

I have tried using aggregate and $unwind, $project and $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操作,我只得到了与原始数据不同的结果数据结构. 是否有可能使结果看起来与原始集合完全一样,但具有新的汇总值?

But I can't get it to reverse the $unwind operation, I only get the resulting data structure to differ from the original. Is it possible to get the result to look exactly like the original collection but with the new aggregated values?

/gemigspam

/gemigspam

推荐答案

如何处理此问题有一个特殊的技巧,但是首先,如果您拥有可用的MongoDB 2.6或更高版本,则实际上可以执行所需的操作而无需使用

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.

此处的主要运算符是 $map 处理适当的数组,并使用 $allElementsTrue 运算符评估您的结果"字段.这里使用"map"可以对内部"tests"数组进行测试,以查看其中的"result"字段都满足真实条件的位置.在外部数组的情况下,可以根据需要将此结果"放入那些文档中,当然,对文档的完整评估遵循相同的规则:

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

在早期版本中执行此操作的方法要求您 $group > 分两步进行,以便在对结果"字段再次进行测试时重建"阵列.此处的另一个区别还在于使用 $min 运算符因为false将被认为是小于true的值,并具有相同的"allElements"概念:

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

这篇关于mongoDB:如何撤消$ unwind的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆