使用 MongoDB 嵌套 Group By 函数

发布于 2024-11-08 18:59:44 字数 1007 浏览 0 评论 0原文

我对 MongoDB 很陌生,是 MySQL 的老手,但遇到了一个小障碍。

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

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

TeamID     Day      AvgAmount
100        4/1   45
200        4/2   50
100         4/2     20

现在我正在尝试汇总这些数据获取每个团队每天的平均订单金额,即:

Day      AvgAmount
4/1     47.5
4/2      35

我可以使用 MySQL 轻松完成此操作,但无法弄清楚如何使用 MongoDB 执行此操作,而无需在应用程序端手动执行此操作,而不是使用MongoDB。

I'm pretty new with MongoDB, long time MySQL guy and am running into a little roadblock.

Given the below sample data:
TeamID Day OrderAmount
100      4/1   50
100      4/1   40
200      4/2   50
100      4/2   20

I'm trying to find the average team order amounts per day. I'm able to do a simple query using mapReduce function to do a group by with the TeamId & Day. So now I have:

TeamID      Day      AvgAmount
100           4/1      45
200           4/2      50
100           4/2      20

Now I'm trying to roll that data up to get the average order amount per team per day which would be:

Day      AvgAmount
4/1      47.5
4/2      35

I can do this easily with MySQL but am having trouble figuring out how to do this with MongoDB without doing it manually in the app side rather than doing it with MongoDB.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谷夏 2024-11-15 18:59:44

您可以使用 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 }
});

You can calculate these aggregates with either map-reduce, or the group() function. I'm using group() because it's a bit simpler and faster, however you should use map-reduce if you need to distribute the query over a sharded cluster.

First load the data:

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 })

Per team, per day:

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 }
});

To roll up daily aggregates, just change the key:

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 }
});
禾厶谷欠 2024-11-15 18:59:44

经过一番研究后,我想出了一个解决方案。由于对 MongoDB 和映射/归约思维不熟悉,我不满意它是最优化的解决方案,因此如果其他人有更好的解决方案,请纠正我。具体来说,我无法获得 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;
    }

After a little research, I was able to come up with a solution. I'm not satisfy that it's the most optimized solution due to being new to MongoDB and map/reduce thinking so if anyone else has something better, please correct me. Specifically, I wasn't able to get a length of arr_team object, so I had to have a counter that incremented.

reduce function:


    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;
    }

Finalize:


function(out) {
      out.avg_team_order_amount = out.total_amount/out.team_count;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文