【问题标题】:Postgresql query array of objects in JSONB fieldPostgreSQL 查询 JSONB 字段中的对象数组
【发布时间】:2015-04-13 16:53:07
【问题描述】:

我在 postgresql 9.4 数据库中有一个表,其中包含一个名为接收器的 jsonb 字段。一些示例行:

[{"id": "145119603", "name": "145119603", "type": 2}]
[{"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "363058213", "name": "363058213", "type": 1}]
[{"id": "1427965764", "name": "1427965764", "type": 1}]
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}]
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "791712670", "name": "791712670", "type": 0}]
[{"id": "895207852", "name": "895207852", "type": 0}]
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}]
[{"id": "1079725696", "name": "1079725696", "type": 0}]

我有一个 id 值列表,并且想要在 jsonb 字段的数组中选择包含具有该列表中任何值的对象的任何行。

这可能吗?我可以制作一个 GIN 索引来加快速度吗?

【问题讨论】:

    标签: postgresql jsonb


    【解决方案1】:

    没有单一的操作可以帮助你,但你有几个选择:

    1.如果要查询的 id 数量很少(且固定),可以使用多个包含运算符 @> 结合 or; f.ex.:

    where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'
    

    一个简单的gin 索引可以帮助您在这里的数据列。

    2. 如果你有可变数量的 id(或者你有很多),你可以使用 json[b]_array_elements() 提取数组的每个元素,建立一个 id 列表,然后使用任意包含运算符 ?| 查询它:

    select *
    from   jsonbtest
    where  to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
             array['1884595530', '791712670'];
    

    很遗憾,您无法索引其中包含子查询的表达式。如果你想索引它,你需要为它创建一个函数:

    create function idlist_jsonb(jsonbtest)
      returns jsonb
      language sql
      strict
      immutable
    as $func$
      select to_json(array(select jsonb_array_elements($1.data) ->> 'id'))::jsonb
    $func$;
    
    create index on jsonbtest using gin (idlist_jsonb(jsonbtest));
    

    在此之后,您可以像这样查询 id:

    select *, jsonbtest.idlist_jsonb
    from   jsonbtest
    where  jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];
    

    注意:我在这里使用了dot notation / computed field,但你不必这样做。

    3.但此时,您不必拘泥于 json[b]:您有一个简单的文本数组,PostgreSQL 也支持。

    create function idlist_array(jsonbtest)
      returns text[]
      language sql
      strict
      immutable
    as $func$
      select array(select jsonb_array_elements($1.data) ->> 'id')
    $func$;
    
    create index on jsonbtest using gin (idlist_array(jsonbtest));
    

    并使用重叠数组运算符&&查询这个计算域:

    select *, jsonbtest.idlist_array
    from   jsonbtest
    where  jsonbtest.idlist_array && array['193623800', '895207852'];
    

    注意:从我的内部测试来看,后一种方案的计算成本比 jsonb 变种要高,但实际上比它快一点。如果性能对您来说真的很重要,您应该同时测试两者。

    【讨论】:

    • @Chrizt0f 这也是我的 1. 方法(ANY 可以用ORed 表达式表示)。通常很难在客户端应用程序中绑定jsonb[],但如果 OP(或对此感兴趣的任何人)可以做到这一点,它也是一个有效的解决方案——但请注意它会多次使用索引,所以我的原始注释仍然适用(如果您有少量(且固定)(原文如此!)要查询的 id 数量)——但使用 ANY 提供非固定数量的 id 的 OFC 会更舒服。
    【解决方案2】:

    我找到了解决方法:
    where data::text similar to '%("id": "145119603"|"id": "1884595530")%'

    【讨论】:

    • 虽然每次扫描都会导致全文搜索,但这很整洁
    猜你喜欢
    • 2017-07-15
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 2016-04-08
    • 2019-02-17
    • 1970-01-01
    相关资源
    最近更新 更多