查询 JSONB 数组

Posted

技术标签:

【中文标题】查询 JSONB 数组【英文标题】:Querying JSONB array 【发布时间】:2022-01-22 00:31:27 【问题描述】:

以下是我的示例 JSONB 数据,其中包含少量元素。我在这个专栏上有一个杜松子酒索引。


  "customer_data": 
    "name": "abc",
    "country": [
      "xyz",
      "abc",
      "def"
    ],
    "account_details": [
      
        "account_id": 1016084,
        "account_branch": "xyz",
        "account_balance": 2000,
        "transaction_dates": [
          20180125,
          20190125,
          20200125,
          20200525
        ]
      ,
      
        "account_id": 1016087,
        "account_branch": "abc",
        "account_balance": 12010,
        "transaction_dates": [
          20180125,
          20190125,
          20200125
        ]
      
    ],
    "incorporated_year": 2020
  

JSONB 国家属性是一个数组。在应用程序中,此列是多选。如果 jsonb 中国家/地区数组中的任何值与任何输入国家/地区值匹配(如 SQL 查询中的 IN 条件),我需要选择数据。我从应用程序以逗号分隔的形式获取输入,该输入使用 string_to_array 并基于与 jsonb 列的匹配进行拆分。除了国家,其他过滤器也通过了。所有这些我结合起来并动态地形成了总过滤标准。如果它与通过的过滤器匹配,我想返回该行。

所以我尝试将 JSONB 中的国家/地区数组属性与传入的输入进行匹配。

以下查询有效。但我觉得它会很慢,因为我需要动态添加其他过滤器并认为将其作为单个表达式来做会更快

SELECT * 
  FROM customer_data_ms.test_customer 
 WHERE customer_Details -> 'customer_data' -> 'country' 
    ?| array['xyz','gkl','jkl']

我希望选择任何值为“xyz”或“gkl”或“jkl”的行。我想将它作为总表达式的一部分包含在内,因为我还将拥有其他过滤条件并尝试以下方式。

SELECT * 
  FROM customer_data_ms.test_customer 
 WHERE customer_Details @? '$.customer_data.country ?| array[''xyz'',''gkl'',''jkl'']'
    
SELECT * 
  FROM customer_data_ms.test_customer 
 WHERE customer_Details @? '$.customer_data.country ?| (array[''xyz'',''gkl'',''jkl''])'
    
ERROR:  syntax error, unexpected $undefined, expecting '(' at or near "|" of jsonpath input
LINE 2: customer_Details @? '$.customer_data.country ?| array[''xyz'...

我正在努力将数组与输入数组进行比较。任何指导都会有很大帮助。

【问题讨论】:

不要使用 JSON 对此类数据进行建模。使用标准化数据模型。 【参考方案1】:

(a) 我猜您的第一个查询是唯一可以与 postgres 一起使用的查询,因为 ?| 运算符未在 jsonpath 语言中实现,请参阅 manual。所以最后两个查询应该会失败。

(b) 如manual 所述:

jsonb 的默认 GIN 操作符类支持查询 ***键存在运算符 ?、?& 和 ?| 运算符和 路径/值存在运算符@>.

因此,应用于customer_Details 列的基本 gin 索引不能在您的第一个查询中使用,因为 ?| 运算符测试第三嵌套级别元素,而不是 customer_Details 列的***元素。可以在您的第一个查询中使用的另一个索引是:

CREATE INDEX new_index ON customer_data_ms.test_customer USING GIN ((customer_Details->'customer_data'->'country'));

(c) 最后,如果您在第一个查询的WHERE 子句中添加一些其他过滤条件,您无法提前确定 postgres 计划器将使用什么策略来执行查询,或者使用 gin 索引上面,或使用其他现有索引,或扫描整个表。 EXPLAIN ANALYSE 将帮助您了解查询的执行计划。如果它不符合您的期望,那么您可以通过修改查询以某种方式强制规划器选择最佳索引。

【讨论】:

【参考方案2】:

jsonpath 是它自己的语言,有自己的运算符。 ?| 是 SQL 运算符,而不是 jsonpath 运算符。据我所知,如果你想用jsonpath写的话,你必须把它写成一系列用||组装的表达式。

【讨论】:

以上是关于查询 JSONB 数组的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sqlalchemy 查询 jsonb 数组

查询 jsonb 数组

如何查询带有数组的jsonb字段

查询jsonb PSQL中数组元素的where子句

PostgreSQL 查询 JSONB 字段中的对象数组

Postgresql:如何查询包含某些值的 JSONb 数组