如何检查mongo中相同文档中的两个值?

时间:2014-11-12 06:28:20

标签: mongodb mongodb-query aggregation-framework

我有以下数据结构 -

{
"_id" : ObjectId("5462f7c2e4b01e902fe359f9"),
"runtime" : 1415772003908,
"myInfo" : [ 

    {
        "name" : "AAA",
        "uuid" : "42089c2d-e3db-14e7-d427-d020881c4820",
        "canName" : [ 
            "naa.60a9800042704577762b45634476337a", 
            "naa.6d867d9c7acd60001aed76eb2c70bd53", 
            "naa.600a09804270457a7a5d455448735330"
        ]
    }, 
    {
        "name" : "BBB",
        "uuid" : "4208b252-5cab-fa1f-7e2e-449a7884c82b",
        "canName" : [ 
            "naa.6d867d9c7acd60001aed76eb2c70bd53"
        ]
    }, 

],
"ds" : [ 
    {
        "luns" : {
            "model" : "Virtual CD/DVD",
            "canName" : "mpx.vmhba32:C0:T0:L0",
            "vendor" : "Linux"
        },
        "vms" : []
    }, 
    {
        "name" : "name1",
        "utilization" : {
            "freeBytes" : 106087579648,
            "sizeBytes" : 107105746944,
            "usedBytes" : 1018167296
        },
        "luns" : {
            "model" : "LUN",
            "canName" : "naa.60a9800032466774352446525768457a",
            "vendor" : "abc"
        },
        "vms" : []
    }, 
    {
        "name" : "name2",
        "utilization" : {
            "freeBytes" : NumberLong(4352638976),
            "sizeBytes" : NumberLong(5100273664),
            "usedBytes" : NumberLong(747634688)
        },
        "luns" : {
            "model" : "LUN",
            "canName" : "naa.60a9800042704577762b456344763376",
            "vendor" : "NETAPP"
        },
        "vms" : [],
        "diskWriteBytes" : 0,
        "diskReadBytes" : 0
    }, 
    {
        "luns" : {
            "model" : "LUN",
            "canName" : "naa.60a98000324667743524465257684631",
            "vendor" : "NETAPP"
        },
        "vms" : []
    }, 
    {
        "name" : "name3",
        "utilization" : {
            "freeBytes" : NumberLong(7191134208),
            "sizeBytes" : NumberLong(11542724608),
            "usedBytes" : NumberLong(4351590400)
        },
        "luns" : {
            "model" : "LUN",
            "canName" : "naa.60a9800042704577762b45634476337a",
            "vendor" : "NETAPP"
        },
        "vms" : [ 
            "BBB"
        ]
    }, 
    {
        "name" : "name4",
        "utilization" : {
            "freeBytes" : NumberLong(550533857280),
            "sizeBytes" : NumberLong(998848331776),
            "usedBytes" : NumberLong(448314474496)
        },
        "luns" : {
            "model" : "MRSASRoMB-4i",
            "canName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
            "vendor" : "LSI"
        },
        "vms" : [ 
            "AAA", 
            "BBB", 
            "CCC", 
            "DDD"
        ],
        "diskWriteBytes" : 0,
        "diskReadBytes" : 8
    }
]
}

我希望将来自luns的canName与来自myinfo的canName数组匹配,来自myinfo的名称出现在ds的vms中。通过匹配,我想从两个字段中获取以下字段。

来自ds-name,utilization,diskReadBytes,diskWriteBytes

来自vms- name,uuid,canName

所以我的输出就像 -

[{
        "name" : "AAA",
        "uuid" : "42089c2d-e3db-14e7-d427-d020881c4820",
        "canName" :"naa.6d867d9c7acd60001aed76eb2c70bd53", 
       "dsname" : "name3",
        "utilization" : {
            "freeBytes" : NumberLong(550533857280),
            "sizeBytes" : NumberLong(998848331776),
            "usedBytes" : NumberLong(448314474496)
        },
        "luns" : {
            "model" : "MRSASRoMB-4i",
            "canonicalName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
            "vendor" : "LSI"
        }
    }, 
    {
        "name" : "BBB",
        "uuid" : "4208b252-5cab-fa1f-7e2e-449a7884c82b",
        "canName" :"naa.60a9800042704577762b45634476337a",
    "dsname" : "name3",
        "utilization" : {
            "freeBytes" : NumberLong(7191134208),
            "sizeBytes" : NumberLong(11542724608),
            "usedBytes" : NumberLong(4351590400)
        },
        "luns" : {
            "model" : "MRSASRoMB-4i",
            "canonicalName" : "naa.60a9800042704577762b45634476337a",
            "vendor" : "LSI"
        }

    }]

1 个答案:

答案 0 :(得分:1)

当然可以。由于您在数组中匹配,因此不是非常简单。但是aggregation framework

可以做到这一点
db.collection.aggregate([
    // Unwind each array to "de-normalize" all of the content
    { "$unwind": "$myInfo" },
    { "$unwind": "$myInfo.canName" },
    { "$unwind": "$ds" },

    // Project with a test where the two fields match
    { "$project": {
        "_id": "$$ROOT",
        "matched": { 
            "$eq": [ 
                "$myInfo.canName", 
                "$ds.luns.canName"
            ]
        }
    }},

    // Filter out everything that did not match
    { "$match": { "matched": true } },

    // Project out to the field structure you want
    { "$project": {
        "_id": 0,
        "name": "$_id.myInfo.name",
        "uuid": "$_id.myInfo.uuid",
        "canName": "$_id.myInfo.canName",
        "dsname": "$_id.ds.name",
        "utilization": "$_id.ds.utilization",
        "luns": "$_id.ds.luns"
    }}
])

使用MongoDB 2.6中引入的$$ROOT,以避免在您测试两个字段匹配的投影中再次列出所有字段名称。传统上,如果您想要或有较低版本,您也可以列出所有字段。

如果您的数组可能非常大,您可能还需要考虑使用MongoDB 2.6及更高版本的$map上的内联处理:

db.collection.aggregate([
    { "$project": {
      "_id": 0,
      "myInfo": {
        "$map": {
          "input": "$myInfo",
          "as": "info",
          "in": {
            "name": "$$info.name",
            "uuid": "$$info.uuid",
            "canName": {
              "$setDifference": [
                { "$map": {
                  "input": "$$info.canName",
                  "as": "ican",
                  "in": {
                    "$setDifference": [
                      { "$map": {
                        "input": "$ds",
                        "as": "ds",
                        "in": {
                          "$cond": [
                            { "$eq": [
                              "$$ican", "$$ds.luns.canName"
                            ]},
                            { 
                                "canName": "$$ican",
                                "dsname": "$$ds.name",
                                "utilization": "$$ds.utilization",
                                "luns": "$$ds.luns"
                            },
                            false
                          ]
                        }
                      }},
                      [false]
                    ]
                  }                      
                }},
                [false]
              ]
            }
          }
        }
      }
    }},
    { "$unwind": "$myInfo" },
    { "$unwind": "$myInfo.canName" },
    { "$unwind": "$myInfo.canName" },
    { "$project": {
        "name": "$myInfo.name",
        "uuid": "$myInfo.uuid",
        "canName": "$myInfo.canName.canName",
        "dsname": "$myInfo.canName.dsname",
        "utilization": "$myInfo.canName.utilization",
        "luns": "$myInfo.canName.luns"
    }}
])

每种情况下的原则保持不变。基本上,这会处理与数组中每个成员的比较,以查看匹配的位置。喜欢将比赛放在一起并且过滤"在没有匹配的地方,返回最终结果。

我实际上得到了"两个"匹配你的" AAA"元素,因为它" canName"数组有两个元素匹配" ds"阵列:

{
    "name" : "AAA",
    "uuid" : "42089c2d-e3db-14e7-d427-d020881c4820",
    "canName" : "naa.60a9800042704577762b45634476337a",
    "dsname" : "name3",
    "utilization" : {
            "freeBytes" : NumberLong("7191134208"),
            "sizeBytes" : NumberLong("11542724608"),
            "usedBytes" : NumberLong("4351590400")
    },
    "luns" : {
            "model" : "LUN",
            "canName" : "naa.60a9800042704577762b45634476337a",
            "vendor" : "NETAPP"
    }
}
{
    "name" : "AAA",
    "uuid" : "42089c2d-e3db-14e7-d427-d020881c4820",
    "canName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
    "dsname" : "name4",
    "utilization" : {
            "freeBytes" : NumberLong("550533857280"),
            "sizeBytes" : NumberLong("998848331776"),
            "usedBytes" : NumberLong("448314474496")
    },
    "luns" : {
            "model" : "MRSASRoMB-4i",
            "canName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
            "vendor" : "LSI"
    }
}
{
    "name" : "BBB",
    "uuid" : "4208b252-5cab-fa1f-7e2e-449a7884c82b",
    "canName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
    "dsname" : "name4",
    "utilization" : {
            "freeBytes" : NumberLong("550533857280"),
            "sizeBytes" : NumberLong("998848331776"),
            "usedBytes" : NumberLong("448314474496")
    },
    "luns" : {
            "model" : "MRSASRoMB-4i",
            "canName" : "naa.6d867d9c7acd60001aed76eb2c70bd53",
            "vendor" : "LSI"
    }
}

您可以使用"名称"将最后$project更改为$group。和" uuid"字段作为_id分组键,然后在所有其他投影字段上使用$first运算符,以便仅保留"第一个"比赛。但这取决于你的意图。