Ecto - Return 记录在单个查询中按日期分组的时间戳

Ecto - Return records with timestamps grouped by date in a single query

目前我在 table 中有一个约会列表,其中包含以下列:

id | start_time (timestamp with tz) | duration (minutes)

为了按 7 天的时间段对这些约会进行分组,我正在获取每天的约会并像这样手动对它们进行分组:

one_hour = 60 * 60
today = DateTime.utc_now()
week = Enum.reduce(0..6, %{}, fn day, acc ->
  date = DateTime.add(today, one_hour * day * 24, :second) 
  just_date = DateTime.to_date(date)
  appointments = (from a in Appointment, where: fragment("?::date", a.start_time) == ^just_date) |> Repo.all
  Map.put(acc, just_date, appointments)
end)

我想知道我是否可以一次获取所有这些记录而不是 7 个不同的数据库调用并获得与下面相同的结果。

{
    "2021-08-03": [
        {
            "id": 1,
            "start_time": "2021-08-03T05:11:30Z",
            "duration": 30
        },
        {
            "id": 2,
            "start_time": "2021-08-03T06:11:30Z",
            "duration": 30
        },
        {
            "id": 3,
            "start_time": "2021-08-03T07:11:30Z",
            "duration": 30
        }
    ],
    "2021-08-04": [
        {
            "id": 4,
            "start_time": "2021-08-04T05:11:30Z",
            "duration": 30
        }
    ],
    "2021-08-05": [
        {
            "id": 5,
            "start_time": "2021-08-05T05:11:30Z",
            "duration": 30
        },
        {
            "id": 6,
            "start_time": "2021-08-05T10:11:30Z",
            "duration": 30
        }
    ],
    "2021-08-06": [],
    "2021-08-07": [],
    "2021-08-08": [],
    "2021-08-09": []
}

到目前为止,我已经尝试过类似下面的查询,但我不确定这是否可以只对数据库进行一次查询,因为 PostgreSQL 不允许输出这样的记录(?)

  def appointments_count_grouped_by_date(query) do
    query
    |> group_by([a], fragment("date(?)", a.start_time))
    |> select([a], %{date: fragment("date(?)", a.start_time), count: count(a.id)})
    |> order_by([a], asc: fragment("date(?)", a.start_time))
  end

  result = Appointment |> appointments_count_grouped_by_date
           |> Repo.all

我会在日期范围内安排所有约会

start_date = Date.utc_today()
end_date = Date.add(start_date, 7)
appointments =
  from a in Appointment,
  where: fragment(
    "?::date BETWEEN ?::date AND ?::date",
    a.start_time, ^start_date, ^end_date)

records = Repo.all(appointments)

然后在 代码中重塑结果。如果你想接收已经分组的结果,inhecting group_by/2 子句应该不复杂。