在 Postgres 中查询对象的 JSON 数组

Chr*_*agg 19 postgresql json

我有一个带有 json 数据字段的 postgres 数据库。我拥有的 json 是一个对象数组:

[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]
Run Code Online (Sandbox Code Playgroud)

我正在尝试返回 JSON 数组中特定键的值,因此在上面的示例中,我想返回 name 的值。

当我使用以下查询时,我只得到一个返回的 NULL 值:

SELECT data->'name' AS name FROM json_test
Run Code Online (Sandbox Code Playgroud)

我假设这是因为它是一个对象数组?是否可以直接寻址名称键?

最终我需要做的是返回每个唯一名称的计数,这可能吗?

谢谢!

Hal*_*Ali 16

你必须UNNEST阵列JSON-对象首先使用功能(json_array_elements 或者jsonb_array_elements如果有jsonb数据类型),则可以通过指定键访问的值。

WITH json_test (col) AS (
  values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
  y.x->'name' "name"
FROM json_test jt, 
LATERAL (SELECT json_array_elements(jt.col) x) y

-- outputs:
name
--------------
"Mickey Mouse"
"Donald Duck"
Run Code Online (Sandbox Code Playgroud)

要获得唯一名称的计数,它与上面的查询类似,除了 count distinct 聚合函数应用于 y.x->>name

WITH json_test (col) AS (
  values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
  COUNT( DISTINCT y.x->>'name') distinct_names
FROM json_test jt, 
LATERAL (SELECT json_array_elements(jt.col) x) y
Run Code Online (Sandbox Code Playgroud)

需要使用->>代替,->因为前者( ->>) 将提取的值转换为文本,支持相等比较(distinct count 需要),而后者( ->) 将值提取为json,不支持相等比较。

或者,转换jsonasjsonb并使用jsonb_array_elements. JSONB支持相等比较,因此可以将 COUNT DISTINCT 与提取一起使用->,即

COUNT(DISTINCT (y.x::jsonb)->'name')
Run Code Online (Sandbox Code Playgroud)


Bru*_*uno 9

您可以使用jsonb_array_elements(使用时jsonb)或json_array_elements(使用时json来扩展数组元素。

例如:

WITH sample_data_array(arr) AS (
    VALUES ('[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]'::jsonb)
)
, sample_data_elements(elem) AS (
    SELECT jsonb_array_elements(arr) FROM sample_data_array
)
SELECT elem->'name' AS extracted_name FROM sample_data_elements;
Run Code Online (Sandbox Code Playgroud)

在这个例子中,sample_data_elements相当于一个表,其中有一个jsonb名为 的列elem,有两行(初始数据中的两个数组元素)。

结果由两行组成(一jsonb列,或者text如果您使用的是类型->>'name'):

 extracted_name
----------------
 "Mickey Mouse"
 "Donald Duck"
(2 rows)
Run Code Online (Sandbox Code Playgroud)

您应该能够像往常一样对它们进行分组和聚合,以返回单个名称的计数。


小智 5

这样做:

SELECT * FROM json_test WHERE (column_name @> '[{"name": "Mickey Mouse"}]');
Run Code Online (Sandbox Code Playgroud)