Postgresql:通过 json 对象数组中的文本查找行

Postgresql: Find row via text in json array of objects

我试图在我的 Postgresql 数据库中查找 json 列包含给定文本的行。

行架构:

id  |  name         |  subitems
-----------------------------------------------------------------
1   |  "item 1"     |  [{name: 'Subitem A'}, {name: 'Subitem B'}]
2   |  "item 2"     |  [{name: 'Subitem C'}, {name: 'Subitem D'}]

我想要的查询结果 'Subitem B'

id  |  name         |  subitems
-----------------------------------------------------------------
1   |  "item 1"     |  [{name: 'Subitem A'}, {name: 'Subitem B'}]

我可以这样搜索第一个子项:

WHERE lower(subitems->0->>\'name\') LIKE '%subitem a%'

但显然我找不到任何其他子项目,但第一个这样。

我可以得到我所有子项的名称:

SELECT lower(json_array_elements(subitems)->>'name') FROM ...

但它给了我 2 行包含名称:

lower
----------------------------------------------------------------
"subitem a"
"subitem b"

我实际需要的是包含该项目的 1 行。

谁能告诉我怎么做?

你快到了。您的查询:

SELECT lower(json_array_elements(subitems)->>'name') FROM foo;

这将为您提供要过滤的内容。如果将其放入子查询中,您将获得所需的结果:

# SELECT *
    FROM foo f1
    WHERE 'subitem a' IN
      (SELECT lower(json_array_elements(subitems)->>'name')
        FROM foo f2 WHERE f1.id = f2.id
      );
 id |  name  |                    subitems                    
----+--------+------------------------------------------------
  1 | item 1 | [{"name": "Subitem A"}, {"name": "Subitem B"}]
(1 row)

编辑添加

好的,要支持 LIKE 式匹配,您必须更深入一点,将子查询放入您的子查询中。由于这有点难读,我改用 common table expressions.

WITH all_subitems AS (
  SELECT id, json_array_elements(subitems)->>'name' AS subitem
    FROM foo),
matching_items AS (
  SELECT id
    FROM all_subitems
    WHERE
      lower(subitem) LIKE '%subitem a%')
SELECT *
  FROM foo
  WHERE
    id IN (SELECT id from matching_items);

这应该可以满足您的需求。请注意,我将对 lower 的调用上移了一个级别,因此它与 LIKE 并排。这意味着过滤条件在一个地方,因此您可以更轻松地切换到正则表达式匹配或其他任何方式。