在聚合结果中重命名阵列子文档

时间:2017-11-03 07:27:40

标签: mongodb aggregation-framework

我正在使用mongodb 3.4。运行我的聚合后,我的结果显示如下。我在两个系列之间进行了连接。

[   {
    "_id": { // rename _id to main
      "id": "ID_001",
      "name": "Fred flinstone Inc"
    },
    "types": [
      {
        "typeId": "TYPE1",
        "locations": [
          {
            "locationName": "Sydney", // rename locationName to name
            "units": [
              {
                "unitId": "PHG_BTG1" // remove the unitId, i just want the value
              }
            ]
          },
          {
            "locationName": "Brisbane",
            "units": [
              {
                "unitId": "PHG_KTN1"
              },
              {
                "unitId": "PHG_KTN2"
              }
            ]
          }
        ]
      }
    ]   } ]

我想将其投影为

[
  {
    "main": {
      "id": "ID_001",
      "name": "Fred flinstone Inc"
    },
    "types": [
      {
        "typeId": "TYPE1",
        "locations": [
          {
            "name": "Sydney",
            "units": [
              "PHG_BTG1"
            ]
          },
          {
            "name": "Brisbane",
            "units": [
              "PHG_KTN1",
              "PHG_KTN2"
            ]
          }
        ]
      }
    ]
  }
]

我该怎么做?我尝试了$ project的各种组合但失败了。 实施例

{ $project: {
  main: "$_id",
  "_id": 0,
  "types.locations.name": "$types.locations.locationName"
}}

将正确重命名locations.name,但该值显示[Sydney,Brisbane]的数组。当我尝试类似于locations.units的东西时,同上它。

我试图再次放松,但它会显示一个空的结果。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

$project仅在您尝试使用它的形式中才真正“包含”或“排他”。因此,虽然您可以"types": { "typeId": 1 }只返回数组中的那些项,但实际上不能仅通过“包含”或“排除”来更改基础结构。

同样如你所发现的那样:

{ "$project": {
  "types.locations.units": "$types.locations.units.unitId"   
}}

与您期望的结果不同,因为MongoDB查看每个值并作为“映射”数组元素:

"types" : [ 
    {
        "locations" : [ 
            {
                "units" : [ 
                    [ 
                        [ 
                            "PHG_BTG1"
                        ], 
                        [ 
                            "PHG_KTN1", 
                            "PHG_KTN2"
                        ]
                    ]
                ]
            }

或者更糟:

{ "$project": {
  "types.typeId": "$types.typeId"
}}

作为:

"types" : [ 
    {
        "typeId" : [ 
            "TYPE1"
        ]
    }
]

所以“数组数组”在这里并不是真正需要的。这让我们了解为什么这实际上是使用您真正想要使用的以下运算符的“速记”。

要“转换”数组,请使用$map

{ "$project": {
  "_id": 0,
  "main": "$_id",
  "types": {
    "$map": {
      "input": "$types",
      "as": "t",
      "in": {
        "typeId": "$$t.typeId",
        "locations": {
          "$map": {
            "input": "$$t.locations",
            "as": "l",
            "in": {
              "name": "$$l.locationName",
              "units": {
                "$map": {
                  "input": "$$l.units",
                  "as": "u",
                  "in": "$$u.unitId"
                }
              }
            }
          }
        }
      }
    }
  }
}}

返回您想要的格式:

{
    "main" : {
        "id" : "ID_001",
        "name" : "Fred flinstone Inc"
    },
    "types" : [ 
        {
            "typeId" : "TYPE1",
            "locations" : [ 
                {
                    "name" : "Sydney",
                    "units" : [ 
                        "PHG_BTG1"
                    ]
                }, 
                {
                    "name" : "Brisbane",
                    "units" : [ 
                        "PHG_KTN1", 
                        "PHG_KTN2"
                    ]
                }
            ]
        }
    ]
}

基本上每个“数组”都被“重新映射”为只返回它实际指定的内部表示的结构。这就是为什么将$map嵌套在其他$map表达式中,以处理每个数组元素的内部数组。

另请注意,由于我们基本上是“重写”"type"属性,因此$project中具有相同名称的属性的默认行为通常是“复制”并保留顺序, "types"实际上是"main"不存在的现有文档结构的一部分。因此"types"将通过标准投影包含“首先”表示。

“重写”意味着这被认为是一个新元素,因此键的顺序现在与投影中的顺序相同,因为"main"先于"type",而不是另一个四处走动。