【问题标题】:Querying a JSON array of objects in Postgres在 Postgres 中查询 JSON 对象数组
【发布时间】:2018-07-10 00:21:11
【问题描述】:

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

[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]

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

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

SELECT data->'name' AS name FROM json_test

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

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

谢谢!

【问题讨论】:

    标签: json postgresql


    【解决方案1】:

    你必须unnest首先使用函数(json_array_elementsjsonb_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"
    

    要获得唯一名称的计数,它与上面的查询类似,除了计数不同的聚合函数应用于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
    

    必须使用->> 而不是->,因为前者(->>)将提取的值转换为文本,支持相等比较(需要不同的计数),而后者(->)将值提取为json,不支持相等比较。

    或者,将json 转换为jsonb 并使用jsonb_array_elementsJSONB 支持相等比较,因此可以使用 COUNT DISTINCT 以及通过-> 提取,即

    COUNT(DISTINCT (y.x::jsonb)->'name')
    

    【讨论】:

    • 不确定您使用的是哪个版本的 PostgreSQL,但使用 COUNT/GROUP BY 对我来说可以同时使用 ->->>。 (使用版本 10 测试。)
    • @Bruno, COUNT(y.x->'name') 将起作用,然而COUNT(DISTINCT y.x->'name') 将不起作用,因为没有为 json / jsonb 类型实现相等比较器,而count distinct 需要检查两个元素是否不同
    • 我想我发现了它为什么对我有用:(a) 我使用的是 jsonb(不是 json)和 (b) 我使用的是版本 10。这是在9.4 版并添加到 JSON 运算符文档中:“表 9.1 中显示的标准比较运算符适用于 jsonb,但不适用于 json。”,因此在这种情况下确实存在相等运算符。跨度>
    • @Bruno,这是一个了不起的发现!谢谢。我一直认为jsonb 不支持比较运算符,因为json 不支持。相应地更新答案。
    • 谢谢!这正是我所需要的!
    【解决方案2】:

    这样做:

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

    【讨论】:

      【解决方案3】:

      您可以使用jsonb_array_elements (when using jsonb) or json_array_elements (when using 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;
      

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

      结果包含两行(一列jsonb,或者如果您使用->>'name',则为text 类型):

       extracted_name
      ----------------
       "Mickey Mouse"
       "Donald Duck"
      (2 rows)
      

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

      【讨论】:

        猜你喜欢
        • 2022-01-18
        • 2013-09-20
        • 1970-01-01
        • 2018-03-29
        • 1970-01-01
        • 2018-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多