Mongodb按内部元素分组

Posted

技术标签:

【中文标题】Mongodb按内部元素分组【英文标题】:Mongodb group by inner element 【发布时间】:2021-12-20 00:24:08 【问题描述】:

我用一个简单的例子来解释我的 mongodb 集合看起来像这样, [

    
        pid: erwer,
        qty: 3,
        LevelDetails: 
            level1:  userId: 1, amount: 10 ,
            level2:  userId: 2, amount: 20 ,
            level3:  userId: 3, amount: 13 ,
        
    ,
    
        pid: qwsdfg,
        qty: 1,
        LevelDetails: 
            level1:  userId: 1, amount: 10 ,
            level2:  userId: 4, amount: 20 ,
            level3:  userId: 3, amount: 13 ,
        
    ,

]

从集合中,我需要每个用户的级别 1、级别 2 和级别 3 的总和。 查询结果应该是这样的 [

         userId1:  TotalLevel1Amount: 20, TotalLevel2Amount: 0, TotalLevel3Amount: 0  ,

         userId2:  TotalLevel1Amount: 0, TotalLevel2Amount: 20, TotalLevel3Amount: 0  ,

         userId3:  TotalLevel1Amount: 0, TotalLevel2Amount: 0, TotalLevel3Amount: 26  ,

         userId4:  TotalLevel1Amount: 0, TotalLevel2Amount: 20, TotalLevel3Amount: 0  
    ]

【问题讨论】:

【参考方案1】:
    $set:通过将 LevelDetails 转换为键值对来添加新字段 _levelDetails$unwind:解构_levelDetails数组。 $group:根据级别 (_levelDetails.k) 有条件地按 _levelDetails.v.userId$sum 分组。 $project: 格式化显示的文档。 $sort(可选):按userID升序排序。
db.collection.aggregate([
  
    $set: 
      _levelDetails: 
        $objectToArray: "$LevelDetails"
      
    
  ,
  
    $unwind: "$_levelDetails"
  ,
  
    $group: 
      _id: "$_levelDetails.v.userId",
      "TotalLevel1Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level1"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      ,
      "TotalLevel2Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level2"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      ,
      "TotalLevel3Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level3"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      
    
  ,
  
    $project: 
      _id: 0,
      userId: "$_id",
      TotalLevel1Amount: 1,
      TotalLevel2Amount: 1,
      TotalLevel3Amount: 1
    
  ,
  
    $sort: 
      userId: 1
    
  
])

Sample Mongo Playground


至键值对: 'userId': // Result

步骤 1 到 3 与之前的解决方案相同。

    $sort(可选):按_id升序排序。 $project:显示带有array 字段的文档(带有属性kv)。 $replaceRoot:将整个文档替换为键(userId)和值(结果)。
db.collection.aggregate([
  
    $set: 
      _levelDetails: 
        $objectToArray: "$LevelDetails"
      
    
  ,
  
    $unwind: "$_levelDetails"
  ,
  
    $group: 
      _id: "$_levelDetails.v.userId",
      "TotalLevel1Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level1"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      ,
      "TotalLevel2Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level2"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      ,
      "TotalLevel3Amount": 
        $sum: 
          $cond: [
            
              "$eq": [
                "$_levelDetails.k",
                "level3"
              ]
            ,
            "$_levelDetails.v.amount",
            0
          ]
        
      
    
  ,
  
    $sort: 
      _id: 1
    
  ,
  
    $project: 
      array: [
        
          k: 
            $toString: "$_id"
          ,
          v: 
            TotalLevel1Amount: "$TotalLevel1Amount",
            TotalLevel2Amount: "$TotalLevel2Amount",
            TotalLevel3Amount: "$TotalLevel3Amount"
          
        
      ]
    
  ,
  
    "$replaceRoot": 
      newRoot: 
        $arrayToObject: "$array"
      
    
  
])

Sample Mongo Playground (To Key-Value Pair)

【讨论】:

以上是关于Mongodb按内部元素分组的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB按数组中的元素分组

Mongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序

MongoDB计数按数组元素分组的数组中的匹配字符串

mongodb 分组统计: 按deviceId、tenant分组,统计总记录条数、求和workload

MongoDB 按 ID 分组,然后按日期分组

MongoDB按聚合查询分组