2017-05-08 217 views
1

運行Postgres 9.6。postgresql - 對json對象的鍵/值查詢

所以我有這個鍵/值查找表,它建立了一個巨大的JSON對象的最深的子值。鑑於這種結構的表:

CREATE TABLE myschema.file_items 
(
    id integer NOT NULL DEFAULT nextval('file_items_id_seq'::regclass), 
    file_id integer NOT NULL, 
    key character varying[] COLLATE pg_catalog."default" NOT NULL, 
    value character varying COLLATE pg_catalog."default", 
    status character varying COLLATE pg_catalog."default", 
    CONSTRAINT file_items_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS = FALSE 
) 
TABLESPACE pg_default; 

ALTER TABLE verification.file_items 
    OWNER to postgres; 

insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog1","description"}', 'val1', 'approved'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog1","cost"}', '100', null); 
insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog1","window"}', '[-200,500]', 'not verified'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog2","description"}', 'val2', 'approved'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog2","cost"}', '200', null); 
insert into file_items (file_id, key, value, status) 
values (1, '{"cogs","cog2","window"}', '[-300,500]', null); 

insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget1","description"}', 'wid1', 'approved'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget1","cost"}', '100', 'approved'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget1","window"}', '[-200,500]', 'not verified'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget2","description"}', 'wid2', null); 
insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget2","cost"}', '300', 'approved'); 
insert into file_items (file_id, key, value, status) 
values (1, '{"widgets","widget2","window"}', '[-1000,700]', null); 

我可以查詢我所有的齒輪像這樣:

select * 
from file_items 
where 'cogs' = any(key) 

我怎麼會逆向工程這個目標?相反,我想以某種方式產生一個JSON對象格式如下:

"cogs": { 
    "cog1": { 
     "description": "val1", 
     "cost":100, 
     "window":[-200,500] 
    }, 
    "cog2": { 
     "description": "val2", 
     "cost":200, 
     "window":[-300,500] 
    } 
} 

請注意,我故意不想要做齒輪對象的數組。它們是齒輪對象的實際屬性。這樣做是因爲我們可以有傳入的json對象,我們不知道它的所有屬性,因此我們使用鍵/值映射表來動態地識別這些屬性值是什麼(即我們不知道我們會事先知道一個「cog67」對象,或者該對象將貼上什麼類型的屬性....)。

由於此查詢最終將從Node.js包('pg'模塊...)觸發,如果我無法通過查詢重新創建json對象,則可能需要在javascript中執行此操作本身。只是想知道是否可以在數據庫級別正確構建json對象並返回它,而不是查詢一堆行並重新構造服務器端代碼中的對象。

任何幫助將不勝感激!謝謝!

回答

2

使用jsonb_object_agg()兩次,聚集的兩個級別(jsonb_pretty()沒有必要的,用於一個不錯的輸出):

select jsonb_pretty(jsonb_build_object(key, jsonb_object_agg(subkey, value))) 
from (
    select key[1], key[2] as subkey, jsonb_object_agg(key[3], value) as value 
    from file_items 
    where 'cogs' = any(key) 
    group by key[1], key[2] 
    ) s 
group by key; 

      jsonb_pretty    
------------------------------------- 
{         + 
    "cogs": {      + 
     "cog1": {     + 
      "cost": "100",   + 
      "window": "[-200,500]",+ 
      "description": "val1" + 
     },       + 
     "cog2": {     + 
      "cost": "200",   + 
      "window": "[-300,500]",+ 
      "description": "val2" + 
     }       + 
    }        + 
} 
(1 row) 
+0

驚人!這次真是萬分感謝。 – dvsoukup