sql - Postgres 9.4 jsonb array as table -


i have json array around 1000 elements of structure "oid: aaa, instance:bbb, value:ccc".

{"_id": 37637070 , "data": [{"oid": "11.5.15.1.4", "value": "1", "instance": "1.1.4"}          , {"oid": "11.5.15.1.9", "value": "17", "instance": "1.1.4"}          , {"oid": "12.5.15.1.5", "value": "0.0.0.0", "instance": "0"}]} 

oid , instance unique per json array. if given option change structure have changed format key:value:

{"11.5.15.1.4-1.1.4":"1", "11.5.15.1.9-1.1.4": "17", "12.5.15.1.5-0": "0.0.0.0"} 

however, if need stay old structure

  1. what fastest way specific oid array?

  2. what fastest way table 3 columns of oid, instance , value. or better pivot table oid+instance column header.

for 2. tried following, pretty slow on large table:

select * (    select a->>'oid' oid, a->>'instance' instance, a->>'value' value1, id    (       select jsonb_array_elements(config#>'{data}')  a, id       configuration       ) b    ) c  oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' , instance = '0' , value1 <> '1'; 

query

your table definition missing. assuming:

create table configuration (   config_id serial primary key , config jsonb not null ); 

to find value , row given oid , instance:

select c.config_id, d->>'value' value   configuration c      , jsonb_array_elements(config->'data') d  -- default col name "value"  d->>'oid'      = '1.3.6.1.4.1.7352.3.10.2.5.35.3' ,    d->>'instance' = '0' ,    d->>'value'   <> '1' 

that's implicit lateral join. compare:

2) fastest way table 3 columns of oid, instance , value.

i suppose use jsonb_populate_recordset(), can provide data types in table definition. assuming text all:

create temp table data_pattern (oid text, value text, instance text); 

could persisted (non-temp) table. 1 current session. then:

select c.config_id, d.*   configuration c      , jsonb_populate_recordset(null::data_pattern, c.config->'data') d 

that's all. first query rewritten:

select c.config_id, d.*   configuration c      , jsonb_populate_recordset(null::data_pattern, c.config->'data') d  d.oid      = '1.3.6.1.4.1.7352.3.10.2.5.35.3' ,    d.instance = '0' ,    d.value   <> '1'; 

but that's slower first query. key performance bigger table index support:

index

you index normalized (translated) table or alternative layout proposed in question. indexing current layout not obvious, possible. best performance suggest functional index on data key jsonb_path_ops operator class. per documentation:

the technical difference between jsonb_ops , jsonb_path_ops gin index former creates independent index items each key , value in data, while latter creates index items each value in data.

this should work wonders performance:

create index configuration_my_idx on configuration using gin ((config->'data') jsonb_path_ops); 

one might expect complete match json array element work, like:

select * configuration  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"                             , "instance": "0", "value": "1234"}]'; 

note json array notation (with enclosing []) of provided value, that's required.

but array elements subset of keys work well:

select * configuration  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"                             , "instance": "0"}]' 

the hard part incorporate seemingly unsuspicious added predicate value <> '1'. care must taken apply predicates same array element. combine first query:

select c.*, d->>'value' value   configuration c      , jsonb_array_elements(config->'data') d  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]' ,    d->>'oid'      = '1.3.6.1.4.1.7352.3.10.2.5.35.3'  -- must repeated ,    d->>'instance' = '0'                               -- must repeated ,    d->>'value'   <> '1'                               -- here can rule out 

voilá.

special index

if table huge, index size may deciding factor. compare performance of special solution functional index:

this function extracts postgres array of oid-instance combinations given jsonb value:

create or replace function f_config_json2arr(_j jsonb)   returns text[] language sql immutable $func$ select array(    select (elem->>'oid') || '-' || (elem->>'instance')      jsonb_array_elements(_j) elem    ) $func$ 

we can build functional index based on this:

create index configuration_conrfig_special_idx on configuration using  gin (f_config_json2arr(config->'data')); 

and base query on it:

select * configuration  f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[] 

the idea index should substantially smaller because stores combined values without keys. array containment operator @> should perform similar jsonb containment operator @>. don't expect big difference, interested faster.

similar first solution in related answer (but more specialized):

asides:

  • i not use oid column name since that's used internal purposes in postgres.
  • if possible, use plain, normalized table without json.

Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -