【问题标题】:Combine arrays when grouping documents对文档进行分组时合并数组
【发布时间】:2018-02-19 15:24:12
【问题描述】:

数据库中的文档格式如下

{
  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']
}

我尝试将它们单独展开并将它们分组。但是当我放松它们时,相同的数字正在重复。请帮帮我

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    根据您的可用版本和实用性,您可能只需应用 $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"
        ]
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多