【问题标题】:Mongo aggregate $group by each day?Mongo每天汇总$group?
【发布时间】:2021-09-07 13:37:28
【问题描述】:

我有一个历史集合,并希望基于该集合创建导出数据库

[{
_id: "...",
value: 10,
at: ISODate("2021-24-06T00:01:02.023")
}, {
_id: ...,
value: 13,
at: ISODate("2021-24-06T00:04:11.211")
}, {
_id: ...,
value: 12,
at: ISODate("2021-24-06T09:11:31.182")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-07T01:33:31.723")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-15T09:32:44.983")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-16T10:43:22.083")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-16T14:43:22.083")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-17T04:25:12.021")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-18T20:13:22.083")
}, {
_id: ...,
value: 40,
at: ISODate("2021-24-19T18:41:22.083")
}]

我必须按小时、天、周公开 3 个选项组

我正在尝试使用 $group 来计算一天中的混合/最大值或平均值,但不知道如何将它们分组到每小时/每天/每周的数据中

我可以按 $cond 分组吗? 因为它对所有情况都非常灵活。

示例:按小时分组,第一时刻 = 2021-24-06T00:00:00.000 期望:

[{
  at: ISODate("2021-24-06T00:00:00.000"),
  max: 13,
  min: 10,
  avg: 21.5
}, {
  at: ISODate("2021-24-06T01:00:00.000"),
}, ..., {
  at: ISODate("2021-24-06T09:00:00.000"),
  max: 12,
  min: 12,
  avg: 12
}]

分组依据 = 天

预期:

[{
  at: ISODate("2021-24-06T00:00:00.000"),
  max: 13,
  min: 10,
  avg: 11.7
}, {
  at: ISODate("2021-24-07T00:00:00.000"),
  max: 40,
  min 40,
  avg: 40,
}]

这是我的想法。创建每个组的第一个时刻,将at 与组的第一个时刻和最后一个时刻进行比较。

例如:按天分组,第一组的第一时刻在:ISODate("2021-24-06T00:00:00.000") -> 最后时刻 = ISODate("2021-24-06T23:59:59.999") -> 分组所有记录属于该组

第二组:ISODate("2021-24-06T00:00:00.000") + 1day = ISODate("2021-24-07T00:00:00.000") -> 最后时刻 = ISODate("2021-24-07T23:59:59.999") -> 组所有记录属于该组

但是如何实现

【问题讨论】:

标签: node.js mongodb group-by aggregation


【解决方案1】:

您可以在 Group By $group 子句中使用 $dateToString 根据 DayHour 对数据进行分组。您可以在 Group By $group 子句中使用 $week 根据 Week 对数据进行分组。

请看下面的代码:

样本数据

按周分组

db.collData.aggregate([
  {
    $group : {
       _id : { $week: '$at' },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

按天分组

db.collData.aggregate([
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%d", date: "$at" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

按小时分组

db.collData.aggregate([
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%dT%H", date: "$at" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

See more details about the $group

See more details about the $dateToString

See more details about the $week

在查询中使用 TimeZone 更新

您可以在$dateToString 表达式中使用timezone。请检查以下示例:

db.collData.aggregate([
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%d", date: "$at", timezone: "-05:00" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

db.collData.aggregate([
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%d", date: "$at", timezone: "+07:00" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

您将在下面的链接中找到有关该表达式的更多信息,包括timezone

MongoDB $dateToString

timezone 在小时示例中添加:

db.collData.aggregate([
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%dT%H", date: "$at", timezone: "+00:30" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

timezone 添加在周示例中:

db.collData.aggregate([
  {
    $group : {
       _id : { $week: { date: '$at', timezone: "-05:00" } },
       averageValue: { $avg: "$value" },
       count: { $sum: 1 }
    }
  },
  {
    $sort : { averageValue: -1 }
  }
])

【讨论】:

  • 我需要按天和奇数小时对数据进行分组,因为 timeZone 不是 UTC +0。例如:按时区 +7 的 2022-12-16 日分组 => 我必须从 UtC +0 的 2022-12-15T14:00:00 到 2022-12-16T13:59:59 获取数据。这就是为什么我不能使用 $group 和 $dateToString,时区可能是 UTC +0.5 所以最小单位是分钟
  • @VũAnhDũng,请检查答案的更新部分。表达式$dateToString 允许timezone
  • 一周怎么样?它还支持时区吗?我可以分组的时间甚至 timeZone 是 +0.5。必须从 0:30 -> 1:30、1:30 -> 2:30 ... 分组
  • 我已通过在小时和周示例中添加 timezone 来更新答案。
  • 我已经完成了使用 $bucket 并尝试了使用 $group 的解决方案。结果是一样的,非常好。我将比较两种方式的性能并选择更好的性能。非常感谢@csharpbd
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
  • 1970-01-01
  • 2022-07-07
  • 2019-11-26
  • 2019-06-23
  • 1970-01-01
相关资源
最近更新 更多