PostgreSql中jsonb中没有键的嵌套搜索

时间:2018-06-12 09:51:16

标签: sql json postgresql

问题是关于从PostgreSQL中的JSON中选择。

例如,应用程序包含jsonb中的翻译数据:

{
  "en":{
    "locale":"en",
    "title":"Title",
    "textShort":"Short text",
    "textFull":"Full text"
  }
  "ru":{
    "locale":"ru",
    "title":"Заголовок",
    "textShort":"Короткий текст",
    "textFull":"Подробный текст"
  }
}

此查询成功运作:

select * 
from content_records 
where translations::json->'en'->>'title' like '%Title.';

但是这个查询需要有关语言环境的信息,但案例是我们对语言环境一无所知,必须为每个语言环境进行搜索,例如:

select * 
from content_records 
where translations::json->'any locale'->>'title' like '%Title.';

在MySQL中,它的工作原理如下:

select * 
from content_records 
where LOWER(JSON_EXTRACT(translations, '$.*.title')) LIKE LOWER(:title);

PostgreSQL中有类似的功能: json_extract_path,但它需要关键字,你不能错过密钥*作为符号*在MySQL中。

问题是 - 在这种情况下如何选择嵌套的JSON?

1 个答案:

答案 0 :(得分:1)

不幸的是,在Postgres中你必须首先“取消”键。

这样的事情:

select t.*, cr.translations
from content_records cr
  cross join lateral jsonb_object_keys(translations) as t(locale)
where lower(cr.translations -> t.locale ->> 'title') like '%title';

请注意,如果标题与多个区域设置匹配,则每个匹配的区域设置将获得一行。如果您不想这样做,可以执行以下操作:

select cr.*
from content_records cr
where exists (select *
              from jsonb_object_keys(cr.translations) as t(locale)
              where lower(cr.translations -> t.locale ->> 'title') like '%title')