JSON 使用 Postgres 在数组中构建对象

JSON Build Object Inside an Array with Postgress

我正在为客户项目构建拖放功能,需要我的数据如下所示:

[ [Array(10)], [Array(5)], [Array(5)], [Array(5)], [Array(5)] ]

每个数组看起来像这样(每个数组都代表患者):

[ {id: 1, reccomendations: [array] } ]

推荐数组更深一层,如下所示:

["providerName1", "providerName2", "providerName3"]

我的数据库是这样设置的:

患者Table

+----+-----------+
| id | bucket_id |
+----+-----------+
|  1 |     1     |
|  2 |     2     |
|  3 |     3     |
|  4 |     4     |
|  5 |     5     |
|  6 |     6     |
|  7 |     2     |
|  8 |     3     |
|  9 |     4     |
| 10 |     5     |
+----+-----------+

patient_provider Table
provider_id 引用 provider.id
patient_id 引用 patiend.id

+----+-------------+-------------+
| id | provider_id | patient_id  |
+----+-------------+-------------+
|  1 |       1     |      1      |
|  2 |       7     |      1      |
|  3 |       3     |      1      |
|  4 |       1     |      2      |
|  5 |       8     |      3      |
|  6 |       7     |      3      |
|  7 |       3     |      4      |
|  8 |       2     |      5      |
|  9 |      11     |      5      |
| 10 |       1     |      6      |
+----+-------------+-------------+

供应商Table
provider_id 引用 provider.id
patient_id 引用 patiend.id

+----+-------------+-------------+
| id | provider_id | patient_id  |
+----+-------------+-------------+
|  1 |       1     |      1      |
|  2 |       7     |      1      |
|  3 |       3     |      1      |
|  4 |       1     |      2      |
|  5 |       8     |      3      |
|  6 |       7     |      3      |
|  7 |       3     |      4      |
|  8 |       2     |      5      |
|  9 |      11     |      5      |
| 10 |       1     |      6      |
+----+-------------+-------------+

供应商Table
有比这更多的行和列,但这是我唯一需要的列

+----+-----------+
| id |  program  |
+----+-----------+
|  1 |   blue    |
|  2 |    red    |
|  3 |   green   |
|  4 |   yellow  |
|  5 |    pink   |
|  6 |   teal    |
+----+-----------+

我运行这个:

SELECT "patient".id, ARRAY_AGG(DISTINCT("provider".program)) as providers FROM "patient"
  LEFT JOIN "patient_provider" ON "patient_provider".patient_id = "patient".id
  LEFT JOIN "provider" ON "provider".id = "patient_provider".provider_id
  GROUP BY "patient".id
  ORDER BY "patient".id ASC;

这将使我获得每个患者的提供者数组。

我也有运行这个:

SELECT JSON_AGG("patient") as patient FROM "patient"
WHERE "patient".bucket_id =1; 

有了这个,我可以获得所有 buckets/columns 和属于这些列的患者。

我一直没能找到将两者组合成我需要的数据结构的方法。我已经阅读了一些关于 JSON Build Objects 的文章——这是可行的方法吗?我该怎么做? 我也愿意在服务器端执行此工作流,使用函数拼接并手动获取我需要的数据结构……如果这是更好的方法。如果您认为那是要走的路,我会怎么做?

谁能帮我,我就去买咖啡!我很乐意通过为他们构建此功能来让我的客户开心!

我用以下语句重新创建了您的案例

create table patient (id serial, bucket_id int);
insert into patient (bucket_id) values (1);
insert into patient (bucket_id) values (2);
insert into patient (bucket_id) values (3);
insert into patient (bucket_id) values (4);
insert into patient (bucket_id) values (5);
insert into patient (bucket_id) values (6);
insert into patient (bucket_id) values (2);
insert into patient (bucket_id) values (3);
insert into patient (bucket_id) values (4);
insert into patient (bucket_id) values (5);

create table patient_provider (id serial, provider_id int, patient_id int);
insert into patient_provider (provider_id, patient_id) values (1,1);
insert into patient_provider (provider_id, patient_id) values (7,1);
insert into patient_provider (provider_id, patient_id) values (3,1);
insert into patient_provider (provider_id, patient_id) values (1,2);
insert into patient_provider (provider_id, patient_id) values (8,3);
insert into patient_provider (provider_id, patient_id) values (7,3);
insert into patient_provider (provider_id, patient_id) values (3,4);
insert into patient_provider (provider_id, patient_id) values (2,5);
insert into patient_provider (provider_id, patient_id) values (11,5);
insert into patient_provider (provider_id, patient_id) values (1,6);

create table provider (id serial, program varchar);
insert into provider (program) values ('blue');
insert into provider (program) values ('red');
insert into provider (program) values ('green');
insert into provider (program) values ('yellow');
insert into provider (program) values ('pink');
insert into provider (program) values ('teal');

现在,使用您的第一个查询,并使用 json_build_object 函数,您可以实现 {id: 1, reccomendations: [array] }(实际上并不需要外部数组)。查询如下

SELECT json_build_object('id',"patient".id, 'reccomendations', ARRAY_AGG(DISTINCT("provider".program))) as obj FROM "patient"
LEFT JOIN "patient_provider" ON "patient_provider".patient_id = "patient".id
LEFT JOIN "provider" ON "provider".id = "patient_provider".provider_id
GROUP BY "patient".id
ORDER BY "patient".id ASC

结果是

                          obj
-------------------------------------------------------
 {"id" : 1, "reccomendations" : ["blue","green",null]}
 {"id" : 2, "reccomendations" : ["blue"]}
 {"id" : 3, "reccomendations" : [null]}
 {"id" : 4, "reccomendations" : ["green"]}
 {"id" : 5, "reccomendations" : ["red",null]}
 {"id" : 6, "reccomendations" : ["blue"]}
 {"id" : 7, "reccomendations" : [null]}
 {"id" : 8, "reccomendations" : [null]}
 {"id" : 9, "reccomendations" : [null]}
 {"id" : 10, "reccomendations" : [null]}
(10 rows)

现在,如果您想汇总上述结果,可以使用 json_agg 函数来完成。这是整体代码

With single_objects as (
    SELECT json_build_object('id',"patient".id, 'reccomendations', ARRAY_AGG(DISTINCT("provider".program))) as obj FROM "patient"
      LEFT JOIN "patient_provider" ON "patient_provider".patient_id = "patient".id
      LEFT JOIN "provider" ON "provider".id = "patient_provider".provider_id
      GROUP BY "patient".id
      ORDER BY "patient".id ASC
      )
select json_agg(obj) from single_objects

和结果

                                                                                                                                                                                                                   json_agg
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [{"id" : 1, "reccomendations" : ["blue","green",null]}, {"id" : 2, "reccomendations" : ["blue"]}, {"id" : 3, "reccomendations" : [null]}, {"id" : 4, "reccomendations" : ["green"]}, {"id" : 5, "reccomendations" : ["red",null]}, {"id" : 6, "reccomendations" : ["blue"]}, {"id" : 7, "reccomendations" : [null]}, {"id" : 8, "reccomendations" : [null]}, {"id" : 9, "reccomendations" : [null]}, {"id" : 10, "reccomendations" : [null]}]
(1 row)

如果确实需要对每个id进行额外的数组封装,只需要在上面提到的json_build_object调用中添加一个json_build_array函数即可。完整查询

With single_objects as (
    SELECT json_build_array(json_build_object('id',"patient".id, 'reccomendations', ARRAY_AGG(DISTINCT("provider".program)))) as obj FROM "patient"
      LEFT JOIN "patient_provider" ON "patient_provider".patient_id = "patient".id
      LEFT JOIN "provider" ON "provider".id = "patient_provider".provider_id
      GROUP BY "patient".id
      ORDER BY "patient".id ASC
      )
select json_agg(obj) from single_objects

最终结果

                                                                                                                                                                                                                             json_agg
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [[{"id" : 1, "reccomendations" : ["blue","green",null]}], [{"id" : 2, "reccomendations" : ["blue"]}], [{"id" : 3, "reccomendations" : [null]}], [{"id" : 4, "reccomendations" : ["green"]}], [{"id" : 5, "reccomendations" : ["red",null]}], [{"id" : 6, "reccomendations" : ["blue"]}], [{"id" : 7, "reccomendations" : [null]}], [{"id" : 8, "reccomendations" : [null]}], [{"id" : 9, "reccomendations" : [null]}], [{"id" : 10, "reccomendations" : [null]}]]
(1 row)