Postgresql,JSONB,如何从对象数组中查询联接字符串

iqih9akk  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(3)|浏览(254)

我在PostgreSQL表中有一个JSONB,它的结构大致是这样的

{
  "obj1": {
    "obj2": {
      "obj3": [
        {
          "obj4": {
            "obj": "A"
          }
        },
        {
          "obj4": {
            "obj": "B"
          }
        }
      ]
    }
  }
}

然后我的obj3是一个对象数组,我想把obj4里面的obj用逗号分隔开。
因此,我真正需要的是:
我正在使用PostgreSQL 14。任何帮助将不胜感激。
而我有这个

SELECT t.id,
       jsonb_path_query(t.b,
                        '$."obj1"."obj2"."obj3"[*]."obj4"."obj"' ::jsonpath) AS obj5
  FROM (VALUES(1,
               '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"A"}},{"obj4":{"obj":"B"}}]}}}'
               ::jsonb), (2,
         '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"C"}},{"obj4":{"obj":"D"}}]}}}'
         ::jsonb), (3, '{}' ::jsonb)) t(id, b);

But the json_path_query multiply the rows and remove not found results as well...
44u64gxh

44u64gxh1#

您需要按t.id对结果行进行分组,以便将A和B以及C和D分组在同一行上,同时使用string_agg函数将它们分组在同一结果列中,并使用','作为分隔符。
但要执行此操作,首先需要将jsonb_path_query函数从SELECT子句切换到FROM子句,同时引入LEFT JOIN,以便保留jsonb_path_query函数中没有输出的行。
解决的办法是:

select t.id, string_agg(obj5->>'obj', ',') AS result
from (
    values (1, '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"A"}},{"obj4":{"obj":"B"}}]}}}'::jsonb), 
    (2, '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"C"}},{"obj4":{"obj":"D"}}]}}}'::jsonb), 
    (3, '{}'::jsonb)
) t(id, b)
left join lateral jsonb_path_query(t.b, '$.obj1.obj2.obj3[*].obj4') as obj5
  on TRUE
group by t.id;

请参阅dbfiddle

vltsax25

vltsax252#

由内而外:爬上对象树,展开数组,然后选择/aggregate。DB fiddle

select id, (
    select string_agg(j->'obj4'->>'obj', ',')
    from jsonb_array_elements(b->'obj1'->'obj2'->'obj3') as j
  ) as objlist
from the_table;

| 标识符|对象列表|
| - -|- -|
| 一个|A、B|
| 2个|C、D|
| 三个||

xqk2d5yq

xqk2d5yq3#

为了清晰/重用,我创建了一个函数将jsonb数组转换为Postgres数组。

CREATE OR REPLACE FUNCTION jsonb_text_array(jsonb)
                   RETURNS text[]
                  LANGUAGE sql
                  PARALLEL SAFE
                 LEAKPROOF
                    STRICT
                        AS $$
  SELECT array_agg(t)
    FROM jsonb_array_elements_text($1) x(t)
  ;
$$;

那么这个查询应该会返回您想要的结果。

SELECT t.id
     , jsonb_text_array(jsonb_path_query_array(t.b, '$.obj1.obj2.obj3.obj4.obj')) AS obj5
  FROM ( VALUES
         (1, '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"A"}},{"obj4":{"obj":"B"}}]}}}'::jsonb)
       , (2, '{"obj1":{"obj2":{"obj3":[{"obj4":{"obj":"C"}},{"obj4":{"obj":"D"}}]}}}'::jsonb)
       , (3, '{}'::jsonb)
       ) t(id, b);

如果您确实希望返回字符串而不是数组,请将函数更改为返回text而不是text[],并使用string_agg(t, ',')而不是array_agg(t)

相关问题