如何从PostgreSQL json中提取数组

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介:

如何从PostgreSQL json中提取数组

作者

digoal

日期

2016-09-10

标签

PostgreSQL , json , 数组 , jsonb


背景

在PostgreSQL中使用JSON类型时,除了能存,大家更关心的是JSON中的数据的使用,例如
1. VALUE支持哪些类型,

通过以下方法可以提取JSON最外层的VALUE的数据类型

json_typeof(json)    
jsonb_typeof(jsonb)    

目前支持的类型如下
object, array, string, number, boolean, and null

2. 包含哪些KEY或VALUE,通过路径提取KEY或VALUE等。

3. 通过制定KEY提取VALUE,
通常通过KEY提取的VALUE还是JSON或JSONB类型,因为JSON本身就是嵌套的,但是可以通过json typeof得知它的类型。

json_typeof(json)    
jsonb_typeof(jsonb)    

但是SQL还是认为他是个JSON,要么就是转换为TEXT。

postgres=# create table t3(c1 jsonb);  
CREATE TABLE  
postgres=# insert into t3 values ('{"a":"v","b":12,"c":{"ab":"hello"},"d":12.3,"e":true,"f":[1,2,3,4],"g":["a","b"]}');  
INSERT 0 1  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'a' col from t3) t;  
 pg_typeof | jsonb_typeof | col   
-----------+--------------+-----  
 jsonb     | string       | "v"  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'b' col from t3) t;  
 pg_typeof | jsonb_typeof | col   
-----------+--------------+-----  
 jsonb     | number       | 12  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'c' col from t3) t;  
 pg_typeof | jsonb_typeof |       col         
-----------+--------------+-----------------  
 jsonb     | object       | {"ab": "hello"}  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'d' col from t3) t;  
 pg_typeof | jsonb_typeof | col    
-----------+--------------+------  
 jsonb     | number       | 12.3  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'e' col from t3) t;  
 pg_typeof | jsonb_typeof | col    
-----------+--------------+------  
 jsonb     | boolean      | true  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'f' col from t3) t;  
 pg_typeof | jsonb_typeof |     col        
-----------+--------------+--------------  
 jsonb     | array        | [1, 2, 3, 4]  
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'g' col from t3) t;  
 pg_typeof | jsonb_typeof |    col       
-----------+--------------+------------  
 jsonb     | array        | ["a", "b"]  
(1 row)  

4. 特定VALUE类型的处理,例如数组。

当VALUE是ARRAY时,如果需要返回ARRAY给SQL层,暂时还没有内置这样的操作符,需要自定义,本文将介绍。

如何返回JSON中存储的数组

大多数JSON操作符,返回的要么是TEXT要么是JSON.

例如以下查询
操作符->返回数组

postgres=# select pg_typeof('{"a":[1,2,3],"b":[4,5,6]}'::json->'a'), '{"a":[1,2,3],"b":[4,5,6]}'::json->'a';  
 pg_typeof | ?column?   
-----------+----------  
 json      | [1,2,3]  
(1 row)  

操作符->>返回text

postgres=# select pg_typeof('{"a":[1,2,3],"b":[4,5,6]}'::json->>'a'), '{"a":[1,2,3],"b":[4,5,6]}'::json->>'a';  
 pg_typeof | ?column?   
-----------+----------  
 text      | [1,2,3]  
(1 row)  

如果明确json_typeof或jsonb_typeof是array,则可以通过以下function将数组转换为行
不管是什么数组,都返回text行

json_array_elements_text(json)  

jsonb_array_elements_text(jsonb)  

postgres=# select pg_typeof(col),col from (select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b') col) t;  
 pg_typeof | col   
-----------+-----  
 text      | 1  
 text      | 2  
 text      | 3  
 text      | 4  
 text      | 5  
 text      | 6  
(6 rows)  

使用数组构造器,可以将多条记录构造为数组。

postgres=# SELECT array(select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'));  
     array       
---------------  
 {1,2,3,4,5,6}  
(1 row)  

postgres=# SELECT pg_typeof(array(select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b')));  
 pg_typeof   
-----------  
 text[]  
(1 row)  

如何转换JSONB数组的类型

如果想构造int[],在构造前,可以将行的输出转换为对应的格式,

postgres=# SELECT array(select (json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'))::int );  
     array       
---------------  
 {1,2,3,4,5,6}  
(1 row)  

postgres=# SELECT pg_typeof(array(select (json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'))::int ));  
 pg_typeof   
-----------  
 integer[]  
(1 row)  

编写JSON数组转换为SQL数组的函数

可以将以上方法转换为函数来使用,输入json typeof == array的json或jsonb对象,输出text数组。
转换jsonb, json array to text array

CREATE OR REPLACE FUNCTION json_arr2text_arr(_js jsonb)  
   RETURNS text[] AS  
$func$  
SELECT ARRAY(SELECT jsonb_array_elements_text(_js))  
$func$  
LANGUAGE sql IMMUTABLE;  


CREATE OR REPLACE FUNCTION json_arr2text_arr(_js json)  
   RETURNS text[] AS  
$func$  
SELECT ARRAY(SELECT json_array_elements_text(_js))  
$func$  
LANGUAGE sql IMMUTABLE;  

转换jsonb, json array to int array

CREATE OR REPLACE FUNCTION json_arr2int_arr(_js jsonb)  
   RETURNS int[] AS  
$func$  
SELECT ARRAY( SELECT (jsonb_array_elements_text(_js))::int )  
$func$  
LANGUAGE sql IMMUTABLE;  

CREATE OR REPLACE FUNCTION json_arr2int_arr(_js json)  
   RETURNS int[] AS  
$func$  
SELECT ARRAY( SELECT (json_array_elements_text(_js))::int )  
$func$  
LANGUAGE sql IMMUTABLE;  

例子

postgres=# select col, pg_typeof(col) from (select json_arr2text_arr(c1->'f') col from t3) t;  
    col    | pg_typeof   
-----------+-----------  
 {1,2,3,4} | text[]  
(1 row)  

postgres=# select col, pg_typeof(col) from (select json_arr2int_arr(c1->'f') col from t3) t;  
    col    | pg_typeof   
-----------+-----------  
 {1,2,3,4} | integer[]  
(1 row)  

postgres=# select col, pg_typeof(col) from (select json_arr2text_arr(c1->'g') col from t3) t;  
  col  | pg_typeof   
-------+-----------  
 {a,b} | text[]  
(1 row)  

应用场景

例如业务系统在JSON中存储了一些ARRAY,这些ARRAY通常会包括一些全包含,全不包含,相交等查询,达到查询的目的。

这里就需要用到数组的包含,相交,不相干操作符来判断,那就会用到前面提到的数组的转换需求。

例子

例如JSON存储的是乐高积木的各属性。

JSON某个KEY存储的数组代表乐高积木对应型号的小零件部件号清单,然后用户需要查询哪些积木型号包含了指定零件编号,这里涉及的就是全包含的查询。

包含'a'零件

postgres=# select * from t3 where json_arr2text_arr(c1->'g') @> array['a'];  
                                                 c1                                                    
-----------------------------------------------------------------------------------------------------  
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}  
(1 row)  

同时包含'a','c'零件

postgres=# select * from t3 where json_arr2text_arr(c1->'g') @> array['a','c'];  
 c1   
----  
(0 rows)  

同时包含1,2零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') @> array[1,2];  
                                                 c1                                                    
-----------------------------------------------------------------------------------------------------  
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}  
(1 row)  

同时包含1,6零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') @> array[1,6];  
 c1   
----  
(0 rows)  

包含1或6零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') && array[1,6];  
                                                 c1                                                    
-----------------------------------------------------------------------------------------------------  
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}  
(1 row)  

即不包含1 也不包含6零件

postgres=# select * from t3 where not(json_arr2int_arr(c1->'f') && array[1,6]);  
 c1   
----  
(0 rows)  

不包含6零件

postgres=# select * from t3 where not(json_arr2int_arr(c1->'f') && array[6]);  
                                                 c1                                                    
-----------------------------------------------------------------------------------------------------  
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}  
(1 row)  

如果你不想转换为INT,那么在条件中也不要使用INT数组

postgres=# select * from t3 where not(json_arr2text_arr(c1->'f') && array['6']);  
                                                 c1                                                    
-----------------------------------------------------------------------------------------------------  
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}  
(1 row)  

索引

为了提升这种查询的速度,我们可以这样建立索引。

postgres=# create index idx_t3_1 on t3 using gin (json_arr2text_arr(c1->'f'));
CREATE INDEX
postgres=# set enable_seqscan=off;
SET
postgres=# explain select * from t3 where json_arr2text_arr(c1->'f') && array['1','6'];
                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 Bitmap Heap Scan on t3  (cost=12.25..16.52 rows=1 width=32)
   Recheck Cond: (json_arr2text_arr((c1 -> 'f'::text)) && '{1,6}'::text[])
   ->  Bitmap Index Scan on idx_t3_1  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (json_arr2text_arr((c1 -> 'f'::text)) && '{1,6}'::text[])
(4 rows)

postgres=# explain select * from t3 where json_arr2text_arr(c1->'f') @> array['1','6'];
                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 Bitmap Heap Scan on t3  (cost=12.25..16.52 rows=1 width=32)
   Recheck Cond: (json_arr2text_arr((c1 -> 'f'::text)) @> '{1,6}'::text[])
   ->  Bitmap Index Scan on idx_t3_1  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (json_arr2text_arr((c1 -> 'f'::text)) @> '{1,6}'::text[])
(4 rows)

参考

http://dba.stackexchange.com/questions/54283/how-to-turn-json-array-into-postgres-array
https://www.postgresql.org/docs/9.6/static/functions-json.html
https://www.postgresql.org/docs/9.6/static/functions-array.html

Count

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
3月前
|
JSON 前端开发 JavaScript
php中JSON或数组到formData的键值对转换
转换JSON或数组到formData格式的键值对并不复杂。PHP的 `json_decode()`与 `http_build_query()`是实现这一转换过程的关键函数。理解这个转换过程对于开发中处理各种AJAX请求时调整数据格式至关重要。这样,无论是处理来自客户端的JSON字符串,还是服务器端的数组数据,都能够灵活地转换为适合网络传输的格式,确保数据交换的顺畅和高效。
89 4
|
3月前
|
SQL JSON 关系型数据库
"SQL老司机大揭秘:如何在数据库中玩转数组、映射与JSON,解锁数据处理的无限可能,一场数据与技术的激情碰撞!"
【8月更文挑战第21天】SQL作为数据库语言,其能力不断进化,尤其是在处理复杂数据类型如数组、映射及JSON方面。例如,PostgreSQL自8.2版起支持数组类型,并提供`unnest()`和`array_agg()`等函数用于数组的操作。对于映射类型,虽然SQL标准未直接支持,但通过JSON数据类型间接实现了键值对的存储与查询。如在PostgreSQL中创建含JSONB类型的表,并使用`->>`提取特定字段或`@>`进行复杂条件筛选。掌握这些技巧对于高效管理现代数据至关重要,并预示着SQL在未来数据处理领域将持续扮演核心角色。
57 0
|
3月前
|
JSON JavaScript 数据格式
Jquery 将 JSON 列表的 某个属性值,添加到数组中,并判断一个值,在不在数据中
Jquery 将 JSON 列表的 某个属性值,添加到数组中,并判断一个值,在不在数据中
75 0
|
5月前
|
JSON 关系型数据库 数据库
PostgreSQL中json_to_record函数的神秘面纱
`json_to_record`是PostgreSQL中的函数,用于将JSON数据转换为RECORD类型,便于查询和分析。基本用法是传入JSON数据,如`SELECT json_to_record('{"name": "张三", "age": 30}'::json);`。还可结合FUNCTION创建自定义函数,实现复杂功能。在实际应用中,它简化了对JSON格式数据的处理,例如筛选年龄大于30的用户。了解并善用此函数能提升数据库操作效率。本文由木头左分享,期待你的点赞和收藏,下次见!
PostgreSQL中json_to_record函数的神秘面纱
|
5月前
|
JSON 关系型数据库 MySQL
MySQL中GROUP_CONCAT与JSON_OBJECT、GROUP BY的巧妙结合:打造高效JSON数组汇总
MySQL中GROUP_CONCAT与JSON_OBJECT、GROUP BY的巧妙结合:打造高效JSON数组汇总
157 1
|
5月前
|
JSON 资源调度 Kubernetes
实时计算 Flink版操作报错合集之解析JSON数组时,遇到报错,该怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
JSON JavaScript 数据格式
1.js动态的往json数据添加新属性和值 2.JSON 和 JS 对象互转 3.对象转化为数组
1.js动态的往json数据添加新属性和值 2.JSON 和 JS 对象互转 3.对象转化为数组
52 0
|
6月前
|
存储 JSON DataWorks
DataWorks产品使用合集之DataWorks将 MongoDB 中的数组类型写入到 DataWorks 的单个字段时,表示为字符串格式而非 JSON 格式如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
75 3
|
6月前
|
SQL JSON 监控
实时计算 Flink版产品使用合集之直接将 JSON 字符串解析为数组的内置函数如何解决
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
6月前
|
JSON 关系型数据库 分布式数据库
PolarDB 开源版通过 parray_gin 实现高效率 数组、JSON 内元素的模糊搜索
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的 价值产出, 将数据变成生产力.本文将介绍PolarDB 开源版通过 parray_gin 实现高效率 数组、JS...
123 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版