如何加入来自 jsonb 列的嵌套值?

Posted

技术标签:

【中文标题】如何加入来自 jsonb 列的嵌套值?【英文标题】:How to join on a nested value from a jsonb column? 【发布时间】:2020-03-17 18:41:15 【问题描述】:

我有一个包含这些表的 PostgreSQL 11 数据库:

CREATE TABLE stats (
   id integer NOT NULL,
   uid integer NOT NULL,
   date date NOT NULL,
   data jsonb DEFAULT '[]'::json NOT NULL
);
INSERT INTO stats(id, uid, date, data) VALUES
   (1, 1, '2020-10-01', '"somerandomhash":"source":"thesource"');

CREATE TABLE links(
   id integer NOT NULL,
   uuid uuid NOT NULL,
   path text NOT NULL
);
INSERT INTO links(id, uuid, path) VALUES
   (1, 'acbd18db-4cc2-f85c-edef-654fccc4a4d8', 'thesource');

我的目标是使用stats 表中的data 创建一个新表reports,但使用links 表中的新键。它看起来像这样:

CREATE TABLE reports(
    id integer NOT NULL,
    uid integer NOT NULL,
    date date NOT NULL,
    data jsonb DEFAULT '[]'::json NOT NULL
);

INSERT INTO reports(id, uid, date, data) VALUES
   (1, 1, 2020-10-01, "uuid":"source":"thesource");

为此,我尝试左加入表links 以检索uuid 列值 - 没有运气:

SELECT s.uid, s.date, s.data->jsonb_object_keys(data)->>'source' as path, s.data->jsonb_object_keys(data) as data, l.uuid
FROM stats s LEFT JOIN links l ON s.data->jsonb_object_keys(data)->>'source' = l.path

我尝试在左连接中使用 s.data->jsonb_object_keys(data)->>'source' 的结果,但报错:

ERROR:  set-returning functions are not allowed in JOIN conditions

我尝试使用LATERAL,但结果仍然无效。 如何使这项工作?

【问题讨论】:

这样的任何问题的工具:Postgres 版本、表定义(CREATE TABLE 脚本)、示例数据、所需结果。 你是对的。我编辑了我的问题。 我冒昧地用可行的方法修复了您的设置。希望我猜对了…… 【参考方案1】:

jsonb_object_keys() 是一个 set-returning 函数,不能按照您的方式使用 - 正如错误消息告诉您的那样。更重要的是,json_object_keys() 返回*** key(s),但您似乎只对 value 感兴趣。改用jsonb_each()

SELECT s.id
     , s.uid
     , s.date
     , jsonb_build_object(l.uuid::text, o.value) AS new_data
FROM   stats s
CROSS  JOIN LATERAL jsonb_each(s.data) o  -- defaults to column names (key, value)
LEFT   JOIN links l ON l.path = o.value->>'source';

db小提琴here

jsonb_each() 返回***键值。仅使用

嵌套的 JSON 对象似乎具有常量键名 'source'。所以连接条件是l.path = o.value->>'source'

最后,使用jsonb_build_object() 构建新的jsonb 值。

虽然这确实有效,但仍有几个问题:

以上假设在stats.data 中总是有一个 ***键。如果没有,您必须定义要做什么...

以上假设在表links 中总是有一个匹配项。如果没有,您必须定义要做什么...

最重要的是: 如果data 与您想象的一样有规律,请考虑一个普通的“uuid”列(或者将其删除,因为值在表links 中)和一个普通的列“source”来替换jsonb柱子。 更简单更高效。

【讨论】:

就是这样。谢谢 !是的,你是对的,我将 uuid 数据移至新列。关于数据,未来它不会只有“来源”,而是更多的数据。但密钥会保持 uuid,因此列会更有效。【参考方案2】:

您似乎想通过 JSON 列中的“源”键加入。

而不是

s.data->jsonb_object_keys(data)->>'source'

试试这个

s.data ->> 'source'

如果我的假设是正确的,整个查询可以这样:

SELECT
  s.uid,
  s.date,
  s.data ->> 'source' AS path,
  s.data -> jsonb_object_keys(data) AS data,
  l.uuid
FROM stats s
LEFT JOIN links l ON s.data ->> 'source' = l.path

【讨论】:

谢谢,但是...我应该发布 json 结构。数据列是这样的:“somehash”:“source”:“sourceidneed”。我正在使用 jsonb_object_keys 来检索“somehash”。在这种情况下它不起作用,它返回 null 作为路径跨度>

以上是关于如何加入来自 jsonb 列的嵌套值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Postgresql 中实现对复杂嵌套 JSONB 的全文搜索

plpgsql jsonb_set 用于带有嵌套数组的 JSON 对象数组

如何在 PostgreSQL JSONB 列中查询具有异构元素的嵌套数组

PostgreSQL:更新JSONB结构中嵌套数组中元素的属性

如何在 Presto 中交叉加入取消嵌套 JSON 数组

如何在spark scala数据框中更新嵌套列的xml值