按聚合中的索引对项目嵌套数组字段值

时间:2016-03-15 22:38:03

标签: mongodb mongodb-query aggregation-framework

我在 MongoDB 中进行聚合,它应该在$project阶段进行数组字段投影。但我无法通过索引访问数组字段:

{//projection stage
  $project: {
    'foo' : { '$ifNull' : ['$bar.0.baz.0.qux', '*'] }
  }
}

这会将foo设置为空数组。 bar是一个多维数组字段。我的MongoDB版本是3.2。如果没有$unwind/$group旧的沉重解决方案的麻烦,我能做些什么呢?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

使用$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
             ]},
            "*"
        ]
    }
}}

因此内部$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 }
        ]
      }
    ]
  })

产地:

{ "_id" : ObjectId("56e8c6b8ff2a05c0da90b31e"), "foo" : 2 }

答案 1 :(得分:1)

将$ arrayElemAt运算符与临时字段一起使用多个$ project阶段。

{$project:{"tmp": {$arrayElemAt:["$bar",0]}}}, {$project:{"tmp2": {$arrayElemAt:["$tmp.baz",0]}}}

比你的价值是$ tmp2.qux。