Postgresql 搜索嵌套的 jsonb 中是否存在

Postgresql search if exists in nested jsonb

我是 jsonb 请求的新手,遇到了问题。在 'Items' table 中,我有 'id' 和 'data' 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 中的值始终是一个包含对象的数组,但有时对象可以具有包含对象的 'fields' 值。最多一层深。

如何 select 项目的 ID,例如包含 "paramId": 3 和 "value": "cat" 的对象,还有一个对象"paramId":5 和 "value" 喜欢“%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%';

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

预先感谢您的帮助。

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

我想要做的是找到所有 'item' 在 'data' 列中符合我的搜索条件的对象。这没有查看对象是在第一层还是在对象的 'fields' 键内。 再举个例子。如果我搜索此记录应该 selected:

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

现在我找到了一个解决方案,但它不是很干净,我不知道它在 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:我"flatten"一级和二级(二级在'fields'键)
B1、B2:这些是我的搜索条件
C:我确保字段符合所有条件。如果有 3 个条件 --> COUNT(*) >=3

我觉得真的不干净。它用于开发目的,但我认为有更好的方法。

如果有人有想法非常感谢him/her!

这可以用 JSON/Path expression 表示,而不需要取消嵌套所有内容

要搜索paramId = 3 and value = 'cat'

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

$[*] 部分遍历第一级数组的所有元素。要检查 fields 数组中的元素,使用 exists() 运算符嵌套表达式。 @.fields[*] 遍历 fields 数组中的所有元素并再次应用相同的表达式。不过,我看不出有什么方法可以避免重复这些值。

对于 "like" 条件,您可以使用 like_regex:

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