PostgreSQL从一组平面记录中生成嵌套JSON的方法

时间:2019-03-01 16:47:19

标签: json postgresql

获得了一个故意非标准化的数据表:

.overlay {
  height: 100%;
  width: height: calc(width);
}

数据...

SELECT location, day, title, teacher, "startTime", "endTime", canceled from "Schedules" ORDER by location, day, "startTime";

并想要生成此JSON:

"First", 1, "Knitting 101", "Doe, John", "2019-02-19T09:00Z", "2019-02-19T11:00Z"
"First", 2, "Model Building 201", "Doe, Jane", "2019-02-20T09:00Z", "2019-02-20T11:00Z"
"Second", 1, "Rocks for Jocks 101", "Smith, Terry", "2019-02-19T09:00Z", "2019-02-19T11:00Z"
"Second", 2, "Speed Reading 101", "Case, Justin", "2019-02-20T09:00Z", "2019-02-20T11:00Z"

当前获取查询结果并使用JavaScript函数将其嵌套。尝试通过这种方法无法成功使用JSON函数:

  1. (从“计划”位置中选择不同的位置,然后按位置排序)l
  2. (从“计划”中选择日期,天,按位置分组,然后按日期,天)
  3. (选择*从“时间表”按位置,日期,“ startTime”排序)c
  4. array_to_json(array_agg(row_to_json(l)))
  5. array_to_json(array_agg(row_to_json(d)))子查询,其中d.location = l.location
  6. array_to_json(array_agg(row_to_json(c)))子查询,其中c.location = l.location和c.day = d.day

这是正确的解决方法还是我错过了一个更优雅的解决方案?

更新:@FXD提供的解决方案是从最详细的组织级别开始,然后倒退。这是有效的查询(对引用大小写混合的对象进行小的调整:

[
  {
    "location": "First",
    "days": [
      {
        "day": 1,
        "classes": [
          {
            "title": "Knitting 101",
            "teacher": "Doe, John",
            "starts": "2019-02-19T09:00Z"
            "ends": "2019-02-19T11:00Z",
            "canceled": false
          }
          ... other classes
        ]
      }
      ... other days
    ]
  }
  ... other locations
]

1 个答案:

答案 0 :(得分:0)

您的步骤正确,但IMO的顺序相反。
如果您构建类,可以按位置/天对它们进行分组,然后按位置对所有天进行分组,最后将整个事物归为一组,则可以有1条记录。

从下面的查询中,我建议您尝试查看T1子查询的功能,然后对T2子查询执行相同的操作。您会发现它并不那么复杂。

SELECT array_to_json(array_agg(LocationClasses ORDER BY Location)) AS FullSchedule
FROM (
    SELECT Location, json_build_object('location',Location, 'days', array_to_json(array_agg(LocationDayClasses ORDER BY day))) AS LocationClasses
    FROM (
        SELECT Location, day, json_build_object('day', Day, 'classes', array_to_json(array_agg(json_build_object('title',Title,'teacher',Teacher,'starts',Starts,'ends',Ends,'cancelled',false) ORDER BY starts))) as LocationDayClasses
        FROM Schedules
        GROUP BY Location, Day
    ) T1
    GROUP BY Location
) T2