【问题标题】:Nested Group By Function with MongoDB使用 MongoDB 按函数嵌套分组
【发布时间】:2011-05-20 23:57:02
【问题描述】:

我是 MongoDB 的新手,长期使用 MySQL 的人,遇到了一个小障碍。

鉴于以下示例数据:
TeamID 日订单金额
100      4/1   50
100      4/1   40
200      4/2   50
100      4/2   20

我正在尝试查找每天的平均团队订单量。我可以使用 mapReduce 函数进行简单查询,以使用 TeamId 和 Day 进行分组。所以现在我有:

团队 ID      天      平均金额
100           4/1      45
200           4/2      50
100           4/2      20

现在我正在尝试汇总这些数据以获得每个团队每天的平均订单量:

天      平均金额
4/1      47.5
4/2      35

我可以用 MySQL 轻松地做到这一点,但我很难弄清楚如何用 MongoDB 做到这一点,而不是在应用程序端手动完成,而不是用 MongoDB 完成。

【问题讨论】:

    标签: mongodb mongoid mongodb-ruby


    【解决方案1】:

    您可以使用 map-reduce 或 group() 函数来计算这些聚合。我使用 group() 是因为它更简单更快,但是如果您需要在分片集群上分发查询,则应该使用 map-reduce。

    首先加载数据:

    db.orders.insert( { teamid: 100, date: "4/1", amount: 50 })
    db.orders.insert( { teamid: 100, date: "4/1", amount: 40 })
    db.orders.insert( { teamid: 200, date: "4/2", amount: 50 })
    db.orders.insert( { teamid: 100, date: "4/2", amount: 20 })
    

    每个团队,每天:

    db.orders.group({
        key: { teamid: true, date: true },
        reduce: function(doc, out) { out.sum += doc.amount; out.count++; },
        initial: { sum: 0, count: 0 },
        finalize: function(out) { out.average = out.sum / out.count }
    });
    

    要汇总每日汇总,只需更改密钥:

    db.orders.group({
        key: { date: true },
        reduce: function(doc, out) { out.sum += doc.amount; out.count++; },
        initial: { sum: 0, count: 0 },
        finalize: function(out) { out.average = out.sum / out.count }
    });
    

    【讨论】:

    • 感谢 Chris,但您的最后一个示例无法说明同一天有 2 个订单的团队。它会根据您的拥有方式计算两次,这是我能够做到的。有没有办法使用某种哈希数据类型来跟踪 TeamID 当天已经下的订单,这样我就不会计算团队两次?
    • @james 你能发布你需要的结果的等效 SQL 吗?
    • 嗨,克里斯,感谢您对它的尝试,请参阅下面的答案。
    【解决方案2】:

    经过一番研究,我想出了一个解决方案。我不满意它是最优化的解决方案,因为它是 MongoDB 的新手和 map/reduce 思维,所以如果其他人有更好的东西,请纠正我。具体来说,我无法获得 arr_team 对象的长度,所以我必须有一个递增的计数器。

    归约函数:

    
        function(doc, prev) { 
          var retVal  = {team_count: 0, day_total: 0};
    
          if(!prev.arr_team[doc.team_id]) {
            prev.arr_team[doc.team_id] = 0;
            prev.team_count++;
          }
    
          prev.arr_team[doc.team_id]++;
    
          prev.order_count++; 
          if(doc.total_amount)
             prev.total_amount += doc.total_amount 
    
          return retVal;
        }
    

    完成:

    
    function(out) {
          out.avg_team_order_amount = out.total_amount/out.team_count;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      相关资源
      最近更新 更多