项目字段由另一个字段的值定义

时间:2017-07-26 20:27:20

标签: mongodb aggregation-framework

我的文档结构如下:

mode: "b",
a: [0,1,2],
b: [1,4,5],
c: [2,2]

我想要投射等于mode的字段。最终结果应该是:

data: [1,4,5] // since mode == "b", it returns b's value

我试过$$CURRENT[$mode],但看起来你不能在mongo中使用这样的括号。我尝试使用像这样的局部变量:

$let: {
    vars: {mode: "$mode"},
    in: "$$CURRENT.$$mode"
}

但这也不起作用。我正在考虑使用$switch,然后手动输入所有可能的模式。但我想知道是否有更好的方法来做到这一点。

1 个答案:

答案 0 :(得分:1)

您正在寻找错误的地方,但是如果您可以使用$switch那么您拥有MongoDB 3.4并且您可以使用$objectToArray这实际上是正确的事情。你的问题是你正在尝试动态地"通过"值"来指代一个财产。它的关键名称"。你不能这样做,所以$objectToArray制作"键" a"值"

所以给你的文件:

{ "mode": "a", "a": [0,1,2], "b": [1,4,5], "c": [2,2] }

然后使用$map$filter进行聚合,将转换后的元素作为数组使用:

db.sample.aggregate([
  { "$project": {
    "_id": 0,
    "mode": 1,
    "data": {
      "$arrayElemAt": [
        { "$map": {
          "input": {
            "$filter": {    
              "input": { "$objectToArray": "$$ROOT" },
              "cond": { "$eq": ["$$this.k","$mode"] }
            }
          },      
          "in": "$$this.v"
        }},
        0
      ]
    }  
  }}
])

或者使用$let$indexOfArray,如果这对您来说更合理:

db.sample.aggregate([
  { "$project": {
    "_id": 0,    
    "mode": 1,
    "data": {
      "$let": {
        "vars": { "doc": { "$objectToArray": "$$ROOT" } },
        "in": {
          "$arrayElemAt": [
            "$$doc.v",
            { "$indexOfArray": [ "$$doc.k", "$mode" ] }
          ]    
        }   
      }
    }
  }}
])

与所选字段匹配:

{
    "mode" : "a",
    "data" : [ 
        0.0, 
        1.0, 
        2.0
    ]
}

如果你看"只是" $objectToArray在这里做了什么,原因应该是不言而喻的:

{
    "data" : [ 
        {
            "k" : "_id",
            "v" : ObjectId("597915787dcd6a5f6a9b4b98")
        }, 
        {
            "k" : "mode",
            "v" : "a"
        }, 
        {
            "k" : "a",
            "v" : [ 
                0.0, 
                1.0, 
                2.0
            ]
        }, 
        {
            "k" : "b",
            "v" : [ 
                1.0, 
                4.0, 
                5.0
            ]
        }, 
        {
            "k" : "c",
            "v" : [ 
                2.0, 
                2.0
            ]
        }
    ]
}

所以现在而不是有一个"对象"使用命名属性,"数组"始终包含"k",命名为"键"和"v"包含"值"。这很容易$filter并获得所需的结果,或者基本上使用任何与数组一起使用的方法来获得匹配。