当前位置: 首页 > 知识库问答 >
问题:

在数组子对象上创建Postgres JSONB索引

贺飞星
2023-03-14

我有一个带有JSONB列myJsonb的表myTable,其数据结构我想像这样索引:

{
  "myArray": [
    {
      "subItem": {
        "email": "bar@bar.com"
      }
    },
    {
      "subItem": {
        "email": "foo@foo.com"
      }
    }
  ]
}

我想在电子邮件上运行索引查询,如:

SELECT *
FROM mytable
WHERE 'foo@foo.com' IN (
  SELECT lower(
      jsonb_array_elements(myjsonb -> 'myArray')
      -> 'subItem'
      ->> 'email'
  )
);

我如何为此创建Postgres JSONB索引?

共有1个答案

詹唯
2023-03-14

如果其中不需要lower(),则查询可以简单高效:

SELECT *
FROM   mytable
WHERE  myjsonb -> 'myArray' @> '[{"subItem": {"email": "foo@foo.com"}}]'

由索引支持:

CREATE INDEX mytable_myjsonb_gin_idx ON mytable
USING  gin ((myjsonb -> 'myArray') jsonb_path_ops);

但匹配是区分大小写的。

如果您需要搜索来匹配忽略大小写,事情会变得更加复杂。

您可以使用与原始查询类似的查询:

SELECT *
FROM   t
WHERE  EXISTS (
   SELECT 1
   FROM   jsonb_array_elements(myjsonb -> 'myArray') arr
   WHERE  lower(arr #>>'{subItem, email}') = 'foo@foo.com'
   );

但是我想不出一个好的方法来使用索引。

相反,我将使用基于提取小写电子邮件数组的函数的表达式索引:

功能:

CREATE OR REPLACE FUNCTION f_jsonb_arr_lower(_j jsonb, VARIADIC _path text[])
  RETURNS jsonb LANGUAGE sql IMMUTABLE AS
'SELECT jsonb_agg(lower(elem #>> _path)) FROM jsonb_array_elements(_j) elem';

索引:

CREATE INDEX mytable_email_arr_idx ON mytable
USING  gin (f_jsonb_arr_lower(myjsonb -> 'myArray', 'subItem', 'email') jsonb_path_ops);

查询:

SELECT *
FROM   mytable 
WHERE  f_jsonb_arr_lower(myjsonb -> 'myArray', 'subItem', 'email') @> '"foo@foo.com"';

虽然这适用于未类型化的字符串文字或实际的jsonb值,但如果您传递textvarchar(如在准备好的语句中),它将停止工作。Postgres不知道如何强制转换,因为输入是模棱两可的。在这种情况下,您需要显式强制转换:

... @> '"foo@foo.com"'::text::jsonb;

或者传递一个不包含双引号的简单字符串,并在Postgres中转换为jsonb

... @> to_jsonb('foo@foo.com'::text);

相关,有更多解释:

  • 查询JSON类型内的数组元素
  • 用于在JSON数组中查找元素的索引
 类似资料:
  • 我需要创建一个对象(银行),其中包含一组客户端和bankID。我的问题是,我不知道如何在主函数中创建银行。 银行类别: 客户端类: 主要类别: 这些是问题所在: 你必须创建一个程序来模拟银行活动。该系统包括以下模块:银行—客户(客户数组)— idBank(字符串)5 BancAccount — accountNumber(字符串)—金额(浮点)客户—姓名(字符串)—地址(字符串)—账户(银行账户数

  • 问题内容: 我是Java的新手,当时我用Java创建了一系列对象。 例如,我有A类 但这只是创建指向A的指针(引用),而不是4个对象。它是否正确?我看到当我尝试访问创建的对象中的函数/变量时,出现空指针异常。为了能够操作/访问对象,我必须这样做 这是正确的还是我做错了什么?如果这是正确的,那真的很奇怪。 编辑:我觉得这很奇怪,因为在C ++中,你只是说新的A [4],它创建了四个对象。 问题答案:

  • 我有Class1类的object1。我想将Class1类扩展到Class2,添加一个方法,然后创建Class2的object2,它在所有方法中的行为都与object1完全相同,只是现在它将有一个额外的方法。 Object1.OldMethod应该具有与Object2.OldMethod完全相同的行为。一个愚蠢的方法是编写一个脚本,用class1继承的100多个方法生成新类: 编辑:很抱歉没有把它说

  • 问题内容: 我有一个需要将对象数组存储在变量中的要求。对象是不同类型的。请参考以下示例: 注意第二个元素是字符串本身的数组。经过研究,我想将其存储为以下接口类型: 尽管如此,我还是遇到了一些无法找到的编译错误。 问题答案: 您要的是可能的- 游乐场链接: 但是您可能不想这样做。您正在与类型系统进行斗争,如果您这样做,我会质疑您为什么要使用Go。考虑利用类型系统- 游乐场链接:

  • 我试图创建一个由子类定义的对象数组(我认为这是正确的术语)。我可以看到这个问题反复出现,但实现仍然存在问题。 我的代码 给出错误 线程“main”java.lang.NullPointerException中出现异常。 为了使其合理化,我将其分解为最简单的术语: 这似乎奏效了。我只是看不出我的两个例子有什么不同。我知道我的第一个没有意义,但是MyClass最终会包含更多的数据。) 我很肯定这个问题

  • 问题内容: 我如何用对象填充ArrayList,而内部的每个对象都不相同? 问题答案: