我有以下数据结构 -
{
"_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"
}
}]
答案 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
运算符,以便仅保留"第一个"比赛。但这取决于你的意图。