【问题标题】:Postgres JSONB: where clause for arrays of arraysPostgres JSONB:数组数组的where子句
【发布时间】:2016-07-05 11:04:19
【问题描述】:

在 postgres 中有(v 9.5,如果重要的话):

create table json_test(
 id varchar NOT NULL,
 data jsonb NOT NULL,
 PRIMARY KEY(id)
);

其中 data 是 json 并且包含数组数组

{
    "attribute": "0",
    "array1": [{
        "id": "a12",
        "attribute": "1",
        "array2": [{
            "id": "a21",
            "attribute": "21"
        }]
    },
    {
        "id": "a12",
        "attribute": "2",
        "array2": [{
            "id": "22",
            "attribute": "22"
        }]
    }]
}

必填:

select id from json_test where 
    json_test->>'attribute'='0' and
    array1.[id='a12'].array2.attribute='22'

查询的意思应该是:给我所有的 id

  1. 一些顶级属性具有特定值
  2. 数组中的特定对象具有必需的属性
  3. 某些对象(来自 array2)特别是 array1 具有必需的属性

诀窍是如何实现最后一个条件。


另一个例子:

{
    "attribute": "0",
    "array1": [{
        "id": "a12",
        "attribute": "1",
        "array2": [{
            "id": "a21_1",
            "attribute_1": "21_1"
        },{
            "id": "a21_2",
            "attribute_2": "21_2"
        }]
    }]
}

select * from json_test where 
    array1.[id='a12'].array2.attribute_1='21_1' and  
    array1.[id='a12'].array2.attribute_2='21_2'

【问题讨论】:

    标签: arrays json postgresql jsonb


    【解决方案1】:

    检索嵌套 json 数组的最通用方法是在横向连接中使用多个 jsonb_array_elements()。示例:

    with json_test(id, data) as (
        values
            (1, 
            '{
                "attribute": "0",
                "array1": [{
                    "id": "a12",
                    "attribute": "1",
                    "array2": [{
                        "id": "a21",
                        "attribute": "21"
                    }]
                },
                {
                    "id": "a12",
                    "attribute": "2",
                    "array2": [{
                        "id": "22",
                        "attribute": "22"
                    }]
                }]
            }'::jsonb)
        )
    
    select id, elem2
    from 
        json_test, 
        jsonb_array_elements(data->'array1') array1(elem1),
        jsonb_array_elements(elem1->'array2') array2(elem2)
    where elem2->>'id' = '22';
    
     id |              elem2              
    ----+---------------------------------
      1 | {"id": "22", "attribute": "22"}
    (1 row)
    

    该方法是通用的,因为您可以轻松访问任何级别的任何 json 对象的任何值,例如:

    ...
    where 
        data->>'attribute' = '0'
        and elem1->>'id' = 'a12'
        and elem2->>'id' = 'a21_1';
    

    【讨论】:

    • 感谢@klin。我一直在看这个方向。但是,我坚持:如果 array2 对象可以用 2 个属性来描述,并且初始 json 在 array2 中包含 2 个对象(一个是第一个,另一个是第二个),那么查询的唯一方法 - 使用连接。 (我会在问题中添加示例)
    • 我不确定我是否完全理解你。我在答案中添加了注释。
    • 问题:当多个属性在同一个数组的不同对象中时。在这种情况下,这些对象属于不同的行(通过 jsonb_array_elements 展平后)
    • 嗯,没有(也不可能)针对同一数组的不同对象的通用方法。这样的对象只需要它们各自的路径。通常情况下,使用这种方法,结果集包含重复的行。然后使用distinct,例如select distinct on (id) * ...
    【解决方案2】:

    扩展 klin 的答案,包括所有测试:

    SELECT j.id
    FROM json_test j
         JOIN LATERAL jsonb_array_elements(j.data->'array1') x(y) ON true
         JOIN LATERAL jsonb_array_elements(x.y->'array2') a(b) ON true
    WHERE j.data->>'attribute'='0'
      AND x.y->>'id' = 'a12'
      AND a.b->>'attribute' = '22';
    

    【讨论】:

      猜你喜欢
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 1970-01-01
      • 2021-06-03
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多