0

我是 jsonb 请求的新手,我遇到了问题。在“项目”表中,我有“id”和“数据”jsonb。这是看起来像数据的内容:

[
  {
    "paramId": 3,
    "value": "dog"
  },
  {
    "paramId": 4,
    "value": "cat"
  },
  {
    "paramId": 5,
    "value": "fish"
  },
  {
    "paramId": 6,
    "value": "",
    "fields": [
      {
        "paramId": 3,
        "value": "cat"
      },
      {
        "paramId": 4,
        "value": "dog"
      }
    ]
  },
  {
    "paramId": 6,
    "value": "",
    "fields": [
      {
        "paramId": 5,
        "value": "cat"
      },
      {
        "paramId": 3,
        "value": "dog"
      }
    ]
  }
]

data 中的值始终是一个包含对象的数组,但有时对象可以具有包含对象的“字段”值。最大深度为一级。

如何选择项目的 id,例如包含“paramId”:3 和“value”:“cat”的对象,并且还有一个带有“paramId”:5 和“value”的对象 LIKE '%ish%' .

当对象处于 0 级时,我已经找到了一种方法来做到这一点

SELECT i.*
FROM items i
JOIN LATERAL jsonb_array_elements(i.data) obj3(val) ON obj.val->>'paramId' = '3'
JOIN LATERAL jsonb_array_elements(i.data) obj5(val) ON obj2.val->>'paramId' = '5'
WHERE obj3.val->>'valeur' = 'cat'
AND obj5.val->>'valeur' LIKE '%ish%';

但如果字段存在,我不知道如何在字段数组中搜索。

预先感谢您的帮助。

编辑:
看起来我的问题不清楚。我会努力让它变得更好。

我想要做的是找到“数据”列对象中符合我的搜索条件的所有“项目”。这无需查看对象是在第一级还是在对象的“字段”键内。再例如。如果我搜索应选择此记录:

  • 'paramId': 3 AND 'value': 'cat
  • 'paramId': 4 AND 'value': LIKE '%og%'

匹配的在 'paramId': 6 对象的 'fields' 键中,我不知道该怎么做。

4

2 回答 2

1

这可以使用JSON/Path 表达式来表达,而无需取消嵌套

搜索 paramId = 3 和 value = 'cat'

select *
from items
where data @? '$[*] ? ( (@.paramId == 3 && @.value == "cat") || exists( @.fields[*] ? (@.paramId == 3 && @.value == "cat")) )'

$[*]部分迭代第一级数组的所有元素。为了检查fields数组中的元素,exists()运算符用于嵌套表达式。@.fields[*]遍历fields数组中的所有元素并再次应用相同的表达式。不过,我看不出如何避免重复这些值。

对于“喜欢”条件,您可以使用 like_regex:

select *
from items
where data @? '$[*] ? ( (@.paramId == 4 && @.value like_regex ".*og.*") || exists( @.fields[*] ? (@.paramId == 4 && @.value like_regex ".*og.*")) )'
于 2020-03-28T09:51:26.817 回答
0

现在我找到了一个解决方案,但它不是很干净,我不知道它在生产中会如何执行 10M 记录。

SELECT i.id, i.data
FROM (                                                    -- A;
         select it.id, it.data, i as value
         from items it,
              jsonb_array_elements(it.data) i
         union
         select it.id, it.data, f as value
         from items it,
              jsonb_array_elements(it.data) i,
              jsonb_array_elements(i -> 'fields') f
     ) as i
WHERE (i.value ->> 'paramId' = '5'                        -- B1;
    AND i.value ->> 'value' LIKE '%ish%')
   OR (i.value ->> 'paramId' = '3'                        -- B2;
    AND i.value ->> 'value' = 'cat')
group by i.id, i.data
having COUNT(*) >= 2;                                     -- C;

A:我将第一层和第二层“展平”(第二层在'fields'键中)
B1,B2:这些是我的搜索条件
C:我确保字段具有所有条件匹配。如果 3 个条件 --> COUNT(*) >=3

在我看来,它真的不干净。它适用于开发目的,但我认为有更好的方法来做到这一点。

如果有人有想法非常感谢他/她!

于 2020-03-28T08:33:01.453 回答