如何汇总数组中的百分比?

时间:2018-07-31 16:16:18

标签: mongodb mongodb-query aggregation-framework

我正在尝试找出如何实现聚合的方法,最后我可以手动将unwindgroup重新组合在一起,但是我确定我应该能够实现一种更简洁的方式,所以我想在卡住时将其丢弃。

我的文档结构(跳过不感兴趣的部分)如下:

{
    _id: ObjectId,
    panels: [
        {
            visConfig: {
                 dataConfig: {
                     columns: [
                         { element: "DX" },
                         { element: "SE" },
                     ]
                 }
            }
        },
        {
            visConfig: {
                 dataConfig: {
                     columns: [
                         { element: "AB" },
                         { element: "XY" },
                     ]
                 }
            }
        }
    ]
}

我想做的是计算element与要提供的给定集合重叠的百分比。因此,例如对于所示文档,它将为集合25%生成["DX"]或为集合50%生成["DX", "AB"]

所以我尝试了一些事情,我认为我已经定居了最近的一个领域:

$project: {
   _id: 1,
   total: { $sum: { $size: "$panels.visConfig.dataConfig.columns" } }
}

但是我在这里得到一个我不明白的错误:

  

$ size的参数必须是一个数组,但类型为:

然后我的条件聚合也遇到了问题,似乎所有元素值都返回0。

{
  _id: 1,
  "panels.visConfig.dataConfig.columns.element": { 
      $sum: {
        $cond: [{
          $setIsSubset: [
            ["DX"], ["$panels.visConfig.dataConfig.columns.element"]
          ] 
        }, 1, 0 ],
      }
  },
}

3 个答案:

答案 0 :(得分:3)

您可以尝试在3.4版本中进行以下汇总。

db.colname.aggregate([
{"$project":{
  "_id":1,
  "total":{
    "$reduce":{
      "input":"$panels.visConfig.dataConfig.columns.element",
      "initialValue":0,
      "in":{"$add":["$$value",{"$size":"$$this"}]}
    }},
    "match":{
      "$sum":{
        "$map":{
          "input":"$panels.visConfig.dataConfig.columns.element",
          "in":{
            "$size":{
              "$setIntersection":[["DX","AB"],"$$this"]
            }
          }
        }
      }
    }
}},
{"$project":{
  "_id":1,
  "percent":{"$multiply":[{"$divide":["$match","$total"]}, 100]}
}}])

更新-您可以在$ reduce管道中执行匹配和总计计算。

db.colname.aggregate([
{"$project":{
  "_id":1,
  "stats":{
    "$reduce":{
      "input":"$panels.visConfig.dataConfig.columns.element",
      "initialValue":{"total":0,"match":0},
      "in":{
        "total":{"$add":["$$value.total",{"$size":"$$this"}]},
        "match":{"$add":["$$value.match",{"$sum":{"$map":{"input":"$$this","in":{"$cond":[{"$in":["$$this", ["DX","AB"]] }, 1, 0]}}}}]}

       }
    }}
}},
{"$project":{
  "_id":1,
  "percent":{"$multiply":[{"$divide":["$stats.match","$stats.total"]}, 100]}
}}])

答案 1 :(得分:1)

您可以使用$map + $reduce来获取所有element值的数组,然后使用$divide可以将$filter-ed {{3 }},总计$size

db.col.aggregate([
    {
        $project: {
            elements: {
                $reduce: {
                    input: { 
                        $map: { 
                            input: "$panels", 
                            as: "panel", 
                            in: "$$panel.visConfig.dataConfig.columns.element" 
                        } 
                    },
                    initialValue: [],
                    in: { $concatArrays: [ "$$this", "$$value" ] }
                }
            }
        }
    },
    {
        $project: {
            percentage: {
                $divide: [ 
                    { 
                        $size: { 
                            $filter: { 
                                input: "$elements", 
                                as: "element", 
                                cond: { 
                                    $in: [ 
                                        "$$element", 
                                        [ "AB", "XY" ] // your input here
                                    ] 
                                } 
                            } 
                        } 
                    },
                    { $size: "$elements" }
                ]
            }
        }
    }
])

答案 2 :(得分:0)

嗯,有几种方法可以做到这一点,但是我这两个管道显示了我将如何做到这一点。

var values = ["DX", "KL"]
  • 第一种方法

    [
       {
          "$project": {
             "percent": {
                "$let": {
                   "vars": {
                      "allsets": {
                         "$reduce": {
                            "input": "$panels.visConfig.dataConfig.columns",
                            "initialValue": [],
                            "in": {
                               "$concatArrays": [ "$$this.element", "$$value" ]
                            }
                         }
                      }
                   },
                   "in": {
                      "$multiply": [
                         {
                            "$divide": [
                               {
                                  "$size": {
                                     "$setIntersection": [ "$$allsets", values ]
                                  }
                               },
                               { "$size": "$$allsets" }
                            ]
                         },
                         100
                      ]
                   }   
                 }
             }
          }
       }
    ]
    
  • 第二种方法与here相同,但是使用了一个管道阶段。

    [
       {
          "$project": {
              "percent": {
                "$multiply": [
                   {
                      "$divide": [
                         {
                            "$sum": {
                               "$map": {
                                  "input": "$panels.visConfig.dataConfig.columns.element",
                                  "in": {
                                     "$size": {
                                       "$setIntersection": [ values, "$$this" ]
                                     }
                                  }
                               }
                            }
                         },
                         {
                            "$reduce": {
                               "input": "$panels.visConfig.dataConfig.columns.element",
                               "initialValue": 0,
                               "in": {
                                  "$add": [ "$$value", { "$size": "$$this" } ]
                               }
                            }
                         }
                      ]
                   },
                   100
                ]
             }
          }
       }
    ]