查询嵌套在 JSON 数组深处的数据的最有效方法?

Most efficient way to query data nested deep in JSON arrays?

目前我正在针对 JSONB table 编写查询,其中包含 800 万多行。如何以最有效的方式查询 parentfriends 对象?

查询(Postgres 9.6):

select distinct id, data->>'_id' jsonID, data->>'email' email, friends->>'name' friend_name, parent->>'name' parent
from temp t
CROSS JOIN jsonb_array_elements(t.data->'friends') friends
CROSS JOIN jsonb_array_elements(friends->'parent') parent
where friends ->> 'name' = 'Chan Franco'
and parent->>'name' = 'Hannah Golden'

示例 DDL(带数据):https://pastebin.com/byN7uyKx

与规范化关系设计一样,您的规则结构化数据会更干净、更小、更快。

就是说,为了使您的设置快很多(如果不如具有匹配索引的规范化设计那么快),添加一个 GIN 索引表达式 data->'friends':

 CREATE INDEX tbl_data_friends_gin_idx ON tbl USING gin ((data->'friends'));

然后使用包含运算符 @>:

向我们的查询添加匹配的 WHERE 子句

SELECT DISTINCT  -- why DISTINCT ?
       id, data->>'_id' AS json_id, data->>'email' AS email
     , friends->>'name' AS friend_name, parent->>'name' AS parent
FROM   tbl t
CROSS  JOIN jsonb_array_elements(t.data->'friends') friends
CROSS  JOIN jsonb_array_elements(friends->'parent') parent
<b>WHERE  t.data->'friends' @> '[{"name": "Chan Franco", "parent": [{"name": "Hannah Golden"}]}]'</b>
AND    friends->>'name' = 'Chan Franco'
AND    parent ->>'name' = 'Hannah Golden';

db<>fiddle here

巨大 区别:在索引的帮助下,Postgres 现在可以在 before 取消嵌套整个 table 中每个嵌套的 "friends" 数组。只有 after 已经识别出基础 table 中的匹配行,jsonb_array_elements() 被调用,并且保留具有合格数组元素的结果行。

请注意,搜索表达式必须有效 JSON,匹配 JSON 数组 data->'friends' 的结构 - 包括外括号 []。但是忽略所有不应用作过滤器的 key/value 对。

相关:

  • Index for finding an element in a JSON array

我避免使用 table 名称 temp,因为这是一个 SQL 关键字,可能会导致混淆错误。请改用名称 tbl