用postgres过滤jsonb上的数据

时间:2018-01-13 20:50:10

标签: sql postgresql jsonb

想象一下,您有人们发布广告的网站。因此,每个广告都有一些选定的属性,例如汽车具有不同的引擎类型,齿轮,颜色等。用户在提交列表之前选择这些属性。 我在列表中以jsonb格式存储选定的属性,查看数据列:

link to image

因此,每个商家信息都包含以下数据:

{
   "properties":[
      {
         "id":"1",
         "value_id":"1"
      },
      {
         "id":"2",
         "value_id":"5"
      },
      {
         "id":"3",
         "value_id":"9"
      },
      {
         "id":"4",
         "value":"2.0"
      },
      {
         "id":"7",
         "value":"2017"
      },
      {
         "id":"6",
         "value":"180.000"
      }
   ]
}

现在,问题是:

1)如何根据json中的id和值来过滤列表?例如,显示列表,其中id = 2,它的值= 5 AND id = 3,它的值= 9,依此类推。我不需要 OR ,我需要 AND 。因此,按多个id和值过滤数据。

2)第一点+比较id和值(大于或小于)的能力。

1 个答案:

答案 0 :(得分:0)

回答第一点,这可能是我第一次使用jsonb[]

t=# with c(a,j) as (values(18,'{
   "properties":[
      {
         "id":"1",
         "value_id":"1"
      },
      {
         "id":"2",
         "value_id":"5"
      },
      {
         "id":"3",
         "value_id":"9"
      },
      {
         "id":"4",
         "value":"2.0"
      },
      {
         "id":"7",
         "value":"2017"
      },
      {
         "id":"6",
         "value":"180.000"
      }
   ]
}'::jsonb), (19,'{"properties":[{"id": "1", "value_id": "1"}]}'))
, m as (select a, array_agg(jb.value)::jsonb[] ar from c, jsonb_array_elements(j->'properties') jb group by a)
select a 
from m 
where '{"id": "1", "value_id": "1"}'::jsonb = any(ar) 
  and '{"id": "3", "value_id": "9"}'::jsonb = any(ar);
 a
----
 18
(1 row)

并且对于第二个要求 - 它不会那么简短,因为你需要进行比较(从而解析json):

t=# with c(a,j) as (values(18,'{
   "properties":[
      {
         "id":"1",
         "value_id":"1"
      },
      {
         "id":"2",
         "value_id":"5"
      },
      {
         "id":"3",
         "value_id":"9"
      },
      {
         "id":"4",
         "value":"2.0"
      },
      {
         "id":"7",
         "value":"2017"
      },
      {
         "id":"6",
         "value":"180.000"
      }
   ]
}'::jsonb), (19,'{"properties":[{"id": "1", "value_id": "1"}]}'))
, m as (select a, jb.value->>'id' id,jb.value->>'value_id' value_id from c, jsonb_array_elements(j->'properties') jb)
, n as (select m.*, count(1) over (partition by m.a)
from m
join c on c.a = m.a and ((id::int >= 1 and value_id::int <2) or (id::int >2 and value_id::int <= 9)))
select distinct a from n
where count > 1;
 a
----
 18
(1 row)

基本想法使用OR获取可能的行,然后检查是否满足所有OR条件