连接子文档数组中的字段

时间:2017-05-30 04:51:26

标签: mongodb aggregation-framework

我正在尝试获取一组结果,其中玩家名称以字符串格式分隔,但我似乎无法使其工作。我可以让player数组连接每个子文档的名字和姓氏,但是将它们连接成一个字符串是失败的。

这是我目前的结果:

{ "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "name" : "Mary Mack" }, { "name" : "Mary Minor" } ], "net" : 4, "team" : 2 }
{ "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "name" : "Jane Doe" }, { "name" : "Julie Doe" } ], "net" : 3, "team" : 3 }
{ "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "name" : "Melanie Maygonuts" }, { "name" : "Mackenzie Mightbecray" } ], "net" : 3, "team" : 4 }
{ "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "name" : "Isabella Iamluny" }, { "name" : "Alexis Alreadythere" } ], "net" : 3, "team" : 5 }

这就是我想要的结果:

{"event" : "Junior Girls 16s", "field" : "Main", "team" : "Mary Mack / Mary Minor", "net" : 4, "team" : 2 }
{ "event" : "Junior Girls 16s", "field" : "Main", "team" : "Jane Doe / Julie Doe", "net" : 3, "team" : 3 }
{ "event" : "Junior Girls 16s", "field" : "Main", "team" : "Melanie Maygonuts / Mackenzie Mightbecray", "net" : 3, "team" : 4 }
{ "event" : "Junior Girls 16s", "field" : "Main", "team" : "Isabella Iamluny / Alexis Alreadythere", "net" : 3, "team" : 5 }

第一组结果的代码:

db.registrations.aggregate([
     {$match: {event: "Junior Girls 16s"}},
     {$project: {event: "$event", field: "$field", net: "$net", team: "$team",
      "players": {
              "$map": {
                  "input": "$players",
                  "as": "u",
                    "in": {
                        "name": { "$concat" : [ "$$u.first", " ", "$$u.last" ] }
                   }
              }
         } }}
 ])

这是我上次尝试的代码,它给出了一个错误无效的运算符reduce:

db.registrations.aggregate([         
    {$match: {event: "Junior Girls 16s"}},         
    {$project: {event: "$event", field: "$field", net: "$net", team: "$team",          
        "players": {                  
            "$map": {                      
                "input": "$players",                      
                "as": "u",                        
                "in": {                            
                    "name": { "$concat" : [ "$$u.first", " ", "$$u.last" ] }                       
                }    
            }
        } 
    }},
    {$project: {event: "$event", field: "$field", net: "$net", team: "$team",
        "players": {
          $reduce: {
            input: "$players",
            initialValue: "",
            in: { $concat: ['$$name', ' / ', '$$this'] }
          }
        }
    }}
    ])

我错过了什么?我觉得我很接近,但却无法操纵我想要的数据。

1 个答案:

答案 0 :(得分:2)

这实际上不应该通过聚合框架来完成,但无论如何我们都会展示这个例子。

如前所述,您的具体错误是因为您没有支持$reduce的MongoDB,这意味着MongoDB 3.4或更高版本。但是,当您进行升级时,您可以执行以下声明:

db.registrations.aggregate([
  { "$addFields": {
    "players": {
      "$reduce": {
        "input": { "$filter": {
          "input": { 
            "$reduce": {
              "input": { "$zip": {
                "inputs": [
                  { "$map": {
                    "input": "$players",
                    "as": "u",
                    "in": { "$concat": [ "$$u.first", " ", "$$u.last" ] }
                  }},
                  { "$map": {
                    "input": {
                      "$range": [ 0, { "$subtract": [ { "$size": "$players" }, 1 ] } ]
                    },
                    "as": "el",
                    "in": " / "
                  }}
                ],
                "useLongestLength": true
              }},
              "initialValue": [],
              "in": { "$concatArrays": [ "$$value", "$$this" ] }
            }
          },
          "as": "el",
          "cond": { "$ne": [ "$$el", null ] }
        }},
        "initialValue": "",
        "in": { "$concat": [ "$$value", "$$this" ] }
      }
    }
  }}
])

这将产生所需的输出:

{
    "_id" : ObjectId("592cfbc3820a42bc1e825de7"),
    "event" : "Junior Girls 16s",
    "field" : "Main",
    "players" : "Mary Mack / Mary Minor",
    "net" : 4,
    "team" : 2
}
{
    "_id" : ObjectId("592cfbc3820a42bc1e825de8"),
    "event" : "Junior Girls 16s",
    "field" : "Main",
    "players" : "Jane Doe / Julie Doe",
    "net" : 3,
    "team" : 3
}
{
    "_id" : ObjectId("592cfbc3820a42bc1e825de9"),
    "event" : "Junior Girls 16s",
    "field" : "Main",
    "players" : "Melanie Maygonuts / Mackenzie Mightbecray",
    "net" : 3,
    "team" : 4
}
{
    "_id" : ObjectId("592cfbc3820a42bc1e825dea"),
    "event" : "Junior Girls 16s",
    "field" : "Main",
    "players" : "Isabella Iamluny / Alexis Alreadythere",
    "net" : 3,
    "team" : 5
}

咀嚼它是不是很满口呢?这就是为什么你不这样做,而只是在客户端代码中读取数据的这种转换。

作为shell的一个简单的JavaScript示例:

db.registrations.find().forEach( doc => {
  doc.players = doc.players
    .map( p => `${p.first} ${p.last}` )
    .join(" / ");
  printjson(doc)
})

输出完全相同的东西。看看现在有多清洁。

源数据

请注意,这个使用的源数据如原始数组内容所具有的问题中所述" first"和"最后"数组中名称的字段:

{ "_id" : ObjectId("592cfbc3820a42bc1e825de7"), "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "first" : "Mary", "last" : "Mack" }, { "first" : "Mary", "last" : "Minor" } ], "net" : 4, "team" : 2 }
{ "_id" : ObjectId("592cfbc3820a42bc1e825de8"), "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "first" : "Jane", "last" : "Doe" }, { "first" : "Julie", "last" : "Doe" } ], "net" : 3, "team" : 3 }
{ "_id" : ObjectId("592cfbc3820a42bc1e825de9"), "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "first" : "Melanie", "last" : "Maygonuts" }, { "first" : "Mackenzie", "last" : "Mightbecray" } ], "net" : 3, "team" : 4 }
{ "_id" : ObjectId("592cfbc3820a42bc1e825dea"), "event" : "Junior Girls 16s", "field" : "Main", "players" : [ { "first" : "Isabella", "last" : "Iamluny" }, { "first" : "Alexis", "last" : "Alreadythere" } ], "net" : 3, "team" : 5 }