如何使用聚合将所选数组值显示为字段

时间:2017-07-27 11:57:08

标签: mongodb mongodb-query aggregation-framework

我有一份如下文件

 {
    "_id" : ObjectId("58b..."),
    "job" : "Plumber",
    "properties": [
        {
            "name" : "First_Name",
            "values": [
                "John"
            ]
        },
        {
            "name" : "Last_Name",
            "values": [
                "Smith"
            ]
        },
        {
            "name" : "Age",
            "values": [
                "28"
            ]
        },
        {
            "name" : "Gender",
            "values": [
                "male"
            ]
        },
        {
            "name" : "Phone_Number",
            "values": [
                "12345"
            ]
        },
        {
            "name" : "city",
            "values": [
                "NY"
            ]
        }
    ]
 }

我需要一个mongodb聚合查询来获取如下文档

 {
    "job" : "Plumber",
    "Name" : "John Smith",
    "Age" : 20,
    "Gender" : "male"
 }

1 个答案:

答案 0 :(得分:1)

我不认为它很好地利用了聚合,但无论如何它仍然存在:

db.sample.aggregate([
  { "$replaceRoot": {
    "newRoot": {
      "$let": {
        "vars": {
          // Make a copy of the array reshaped
          "props": {
            "$map": {
              "input": "$properties",
              "as": "p",
              "in": {
                "k": "$$p.name",
                "v": { "$arrayElemAt": [ "$$p.values", 0 ] }  
              }
            }    
          }
        },
        "in": {
         "$arrayToObject": {    // Converts k and v array to object
           "$concatArrays": [
             [
               // Plain field object
               { "k": "job", "v": "$job" },
               // Join First_Name and Last_Name into one string
               { 
                 "k": "name",
                 "v": {
                   "$concat": [
                     { "$arrayElemAt": [
                       "$$props.v",
                       { "$indexOfArray": [ "$$props.k", "First_Name" ] }
                     ]},
                     " ",
                     { "$arrayElemAt": [
                       "$$props.v",
                       { "$indexOfArray": [ "$$props.k", "Last_Name" ] }
                     ]},
                   ]
                 }
               }
             ],
             // Exclude First_Name and Last_Name entries from the array
             { "$filter": {
               "input": "$$props",
               "cond": { "$not": { "$in": [ "$$this.k", ["First_Name","Last_Name"] ] } }
             }}
           ]            
          }
        }
      }
    }
  }}
])

在客户端代码中,这与shell示例相同:

db.sample.find().map( doc => 
  Object.assign(
    // Just assign the plain field, to "merge" with:
    { job: doc.job },
    // Joined array of two parts
    [].concat.apply(
      // Join First_Name and Last_Name entries in a single item
      [{ 
        "k": "name",
        "v": doc.properties.map(p => ({ k: p.name, v: p.values[0] }) )
          .filter(p => ["First_Name","Last_Name"].indexOf(p.k) !== -1 )
        .map( p => p.v).join(" ")
      }],
      // Exclude First_Name and Lasst_Name entries from array
      doc.properties.map(p => ({ k: p.name, v: p.values[0] }) )
        .filter(p => ["First_Name","Last_Name"].indexOf(p.k) === -1 )
    )
    // Map keys and values
    .map( p => ({ [p.k]: p.v }))
    // Reduce array into single object
    .reduce((acc,curr) => Object.assign(acc,curr),{})
  )
)

两者都产生:

{
    "job" : "Plumber",
    "name" : "John Smith",
    "Age" : "28",
    "Gender" : "male",
    "Phone_Number" : "12345",
    "city" : "NY"
}

所以通常说这不是你使用.aggregate()的原因,因为你只需编写代码来处理游标上的结构变化。但是,如果您需要"稍后聚合"的格式,那么请继续这样做。