在分组文档时组合数组

时间:2017-09-11 11:36:52

标签: mongodb mongodb-query aggregation-framework

数据库中的文件格式如下

{
  product: 'product1',
  state: 'state1',
  nondnd: [1, 2, 3],
  dnd: [4, 5],
  land: [],
  emails: ['a', 'b', 'c']
},
{
  product: 'product1',
  state: 'state1',
  nondnd: [9, 8, 2],
  dnd: [10, 7, 11],
  land: [2, 4, 6, 8],
  emails: ['d']
},
{
  product: 'product1',
  state: 'state2',
  nondnd: [9, 8, 2],
  dnd: [10, 7, 11],
  land: [1, 3],
  emails: ['e', 'g']
}

我需要在产品和产品的基础上对上述文件进行分组。陈述并以下面的格式获取它们

{
  _id: {
    product: 'product1',
    state: 'state1'
  },
  nondnd: [1, 2, 3, 9, 8, 2],
  dnd: [4, 5, 10, 7, 11],
  land: [2, 4, 6, 8],
  emails: ['a', 'b', 'c', 'd']
},
{
  _id:{
    product: 'product1',
    state: 'state2'
  },
  nondnd: [2, 5, 8],
  dnd: [1, 4, 7],
  land: [1, 3],
  emails: ['e', 'g']
}

我试图单独解开它们并将它们分组。但当我解开它们时,相同的数字正在重复。请帮帮我

1 个答案:

答案 0 :(得分:2)

根据您的可用版本和实用性,您可以只应用$reduce$concatArrays,以便在分组文档中“加入”生成的“数组数组”:

db.getCollection('stuff').aggregate([
  { "$group": {
    "_id": {
      "product": "$product", "state": "$state"
    },
    "nondnd": { "$push": "$nondnd" },
    "dnd": { "$push": "$dnd" },
    "land": { "$push": "$land" },
    "emails": { "$push": "$emails" }
  }},
  { "$addFields": {
    "nondnd": {
      "$reduce": {
        "input": "$nondnd",
        "initialValue": [],
        "in": { "$concatArrays": [ "$$value", "$$this" ] }
      }
    },
    "dnd": {
      "$reduce": {
        "input": "$dnd",
        "initialValue": [],
        "in": { "$concatArrays": [ "$$value", "$$this" ] }
      }
    },
    "land": {
      "$reduce": {
        "input": "$land",
        "initialValue": [],
        "in": { "$concatArrays": [ "$$value", "$$this" ] }
      }
    },
    "emails": {
      "$reduce": {
        "input": "$emails",
        "initialValue": [],
        "in": { "$concatArrays": [ "$$value", "$$this" ] }
      }
    }      
  }}
])

甚至是“超现代”,你真的不喜欢重复自己(但你可能应该生成管道阶段):

db.getCollection('stuff').aggregate([
  { "$project": {
    "product": 1,
    "state": 1,
    "data": {
      "$filter": {
        "input": { "$objectToArray": "$$ROOT" },
        "cond": { "$in": [ "$$this.k", ["nondnd","dnd","land","emails"] ] }  
      }  
    }  
  }},
  { "$unwind": "$data" },
  { "$unwind": "$data.v" },
  { "$group": {
    "_id": {
      "product": "$product",
      "state": "$state",
      "k": "$data.k"
    },
    "v": { "$push": "$data.v" }    
  }},
  { "$group": {
    "_id": {
      "product": "$_id.product",
      "state": "$_id.state"  
    },
    "data": { "$push": { "k": "$_id.k", "v": "$v" } }  
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": {
        "$concatArrays": [
          [{ "k": "_id", "v": "$_id" }],
          { "$map": {
            "input": ["nondnd","dnd","land","emails"],
            "in": {
              "$cond": {
                "if": { "$ne": [{ "$indexOfArray": [ "$data.k", "$$this" ] },-1] },
                "then": { 
                  "$arrayElemAt": [
                    "$data",
                    { "$indexOfArray": [ "$data.k", "$$this" ] }
                  ]
                },
                "else": { "k": "$$this", "v": [] }
              }
            }
          }}
        ]
      }
    }
  }}
])

或者您可以在源处交替连接数组并将它们映射到类型。然后在分组后重建:

db.getCollection('stuff').aggregate([
  { "$project": {
    "product": 1,
    "state": 1,
    "combined": {
      "$concatArrays": [
        { "$map": {
          "input": "$nondnd",
          "in": { "t": "nondnd", "v": "$$this" }
        }},
        { "$map": {
          "input": "$dnd",
          "in": { "t": "dnd", "v": "$$this" }  
        }},
        { "$map": {
          "input": "$land",
          "in": { "t": "land", "v": "$$this" }
        }},
        { "$map": {
          "input": "$emails",
          "in": { "t": "emails", "v": "$$this" }    
        }}
      ]        
    }
  }},
  { "$unwind": "$combined" },
  { "$group": {
    "_id": {
      "product": "$product", "state": "$state"
    },
    "combined": { "$push": "$combined" }      
  }},
  { "$project": {
    "nondnd": {
      "$map": {
        "input": {
          "$filter": {
            "input": "$combined",
            "cond": { "$eq": [ "$$this.t", "nondnd" ] }
          }
        },
        "in": "$$this.v"
      }  
    },
    "dnd": {
      "$map": {
        "input": {
          "$filter": {
            "input": "$combined",
            "cond": { "$eq": [ "$$this.t", "dnd" ] }
          }
        },
        "in": "$$this.v"
      }  
    },
    "land": {
      "$map": {
        "input": {
          "$filter": {
            "input": "$combined",
            "cond": { "$eq": [ "$$this.t", "land" ] }
          }
        },
        "in": "$$this.v"
      }  
    },
    "emails": {
      "$map": {
        "input": {
          "$filter": {
            "input": "$combined",
            "cond": { "$eq": [ "$$this.t", "emails" ] }
          }
        },
        "in": "$$this.v"
      }  
    }  
  }}
])

在构建和解构单个连接数组的内容时,很大程度上取决于$map$filter,这对于$unwind来说当然是完全正确的。

同样的结果来自每个案例:

/* 1 */
{
    "_id" : {
        "product" : "product1",
        "state" : "state2"
    },
    "nondnd" : [ 
        9.0, 
        8.0, 
        2.0
    ],
    "dnd" : [ 
        10.0, 
        7.0, 
        11.0
    ],
    "land" : [ 
        1.0, 
        3.0
    ],
    "emails" : [ 
        "e", 
        "g"
    ]
}

/* 2 */
{
    "_id" : {
        "product" : "product1",
        "state" : "state1"
    },
    "nondnd" : [ 
        1.0, 
        2.0, 
        3.0, 
        9.0, 
        8.0, 
        2.0
    ],
    "dnd" : [ 
        4.0, 
        5.0, 
        10.0, 
        7.0, 
        11.0
    ],
    "land" : [ 
        2.0, 
        4.0, 
        6.0, 
        8.0
    ],
    "emails" : [ 
        "a", 
        "b", 
        "c", 
        "d"
    ]
}