【问题标题】:filter data on jsonb with postgres使用 postgres 过滤 jsonb 上的数据
【发布时间】:2018-01-13 20:50:10
【问题描述】:

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

.

因此,每个列表都包含如下数据:

{
   "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 和 value 过滤列表?例如,显示 id = 2 并且它的值 = 5 并且 id = 3 并且它的值 = 9 的列表,依此类推。我不需要OR,我需要AND。因此,按多个 id 和 value 过滤数据。

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

【问题讨论】:

  • 从示例看来,您在 jsonb 中存储的应该是单独的表。
  • @Justinas Marozas,在一个单独的表中,我有这些属性的翻译和其他元数据。那是因为网站有多种语言。我将这些值和 id 加入到其他表中。
  • 但是你为什么要使用 jsonb 来处理这些具有规则结构的数据呢?为什么不单独的三列表(完整的 FK)?甚至是像array['{"id":"1","value_id":"1"}'::jsonb, '{"id":"2","value_id":"5"}', ...]这样的jsonb数组?

标签: sql postgresql jsonb


【解决方案1】:

回答第一点,这可能是我第一次找到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 条件

【讨论】:

  • 是的,这真的不是一个简短的查询。经过我的研究,我想我会同意上面的其他 cmets,最好为值和键创建一个单独的表,就是这样。更容易 - 更好。
  • 显然创建表,而不是将其数据保存在 jsonb 中是更好的主意 :) 我在回答你的问题 - 你如何查询它,而不是解决规范化问题
猜你喜欢
  • 2022-01-02
  • 2017-10-14
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
相关资源
最近更新 更多