按聚合中的索引投影嵌套数组字段值

Ram*_*min 4 mongodb mongodb-query aggregation-framework

我正在MongoDB中进行聚合,它的$projectstage应该有一个数组字段投影。但我无法通过它们的索引访问数组字段:

{//projection stage
  $project: {
    'foo' : { '$ifNull' : ['$bar.0.baz.0.qux', '*'] }
  }
}
Run Code Online (Sandbox Code Playgroud)

这设置foo为一个空数组。bar 是一个多维数组字段。我的 MongoDB 版本是 3.2 。如果没有$unwind/$group旧的繁重解决方案的麻烦,我该怎么办?

谢谢你的帮助 。

Bla*_*ven 5

使用$slice,$map$arrayElemAt

{ "$project": {
    "foo": {
        "$ifNull": [
            { "$arrayElemAt": [
                { "$map": {
                    "input": { "$slice": [
                        { "$map": {
                            "input": { "$slice": [ "$bar", 0, 1 ] },
                            "as": "el",
                            "in": "$$el.baz"
                        }},
                        0, 1
                    ]},
                    "as": "el",
                    "in": { "$arrayElemAt": [ "$$el.qux", 0 ] }
                 }},
                 0
             ]},
            "*"
        ]
    }
}}
Run Code Online (Sandbox Code Playgroud)

因此,内部$map运算符允许您只从每个数组中选择特定字段,您可以$slice在所需位置仅返回该元素。即0,1是零索引和只有一个元素。

对于您刚刚使用$arrayElemAt并检索索引元素的最终结果数组,将其转换为单个值。

当然,$ifNull根据您的结构,测试可能需要更多参与,好像它不一致那么您可能需要检查每个$map输入并相应地交换结果。

但一般过程是:

  • $map 获取字段
  • $slice 从减少数组 $map
  • $arrayElemAt 在最终的数组结果上。

在这样的事情上:

  db.foo.insert({
    "bar": [
      { 
        "baz": [
          { "qux": 2 },
          { "qux": 5 }
        ]
      },
      {
        "baz": [
          { "qux": 3 },
          { "qux": 4 }
        ]
      }
    ]
  })
Run Code Online (Sandbox Code Playgroud)

产生:

{ "_id" : ObjectId("56e8c6b8ff2a05c0da90b31e"), "foo" : 2 }
Run Code Online (Sandbox Code Playgroud)