“ERROR: malformed array literal” saat menggunakan json_to_record dengan elemen array JSON di Postgres 9.4

9

Ini menggambarkan masalah dengan baik:

Ketika kolom b adalah tipe teks, dan bukan array, yang berikut berfungsi:

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text, d text);

 a |         b          | d
---+--------------------+---
 1 | ["hello", "There"] |

Tetapi jika saya mendefinisikan bkolom sebagai array, saya mendapatkan kesalahan ini:

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text[], d text)

ERROR:  malformed array literal: "["hello", "There"]"
DETAIL:  "[" must introduce explicitly-specified array dimensions.

Bagaimana saya bisa meyakinkan / memaksa json_to_record(atau json_populate_record) untuk mengubah array JSON menjadi array Postgres dari tipe kolom target?

Taytay
sumber

Jawaban:

6

Hanya sedikit variasi pada jawaban Chris:

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM json_to_record('{"a": 1, "b": ["hello", "There"], "c": "bar"}')
AS x(a int, b text, d text);

Idenya sama: memijat array JSON menjadi sebuah array - dalam hal ini, melalui array literal. Selain kode yang tampak lebih bersih (walaupun saya menyukainya, regex biasanya tidak banyak membantu dalam hal ini :), sepertinya juga lebih cepat, juga:

CREATE TABLE jsonb_test (
    id serial,
    data jsonb
);

INSERT INTO jsonb_test (id, data)
SELECT i, format('{"a": %s, "b": ["foo", "bar"], "c": "baz"}', i::text)::jsonb 
FROM generate_series(1,10000) t(i);

SELECT a, string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

-- versus 

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

Pada dataset ini dan pada kotak pengujian saya, versi regex menunjukkan dan waktu eksekusi rata-rata 300 ms , sedangkan versi saya menunjukkan 210 ms .

dezso
sumber
1

Ini mungkin bukan solusi yang paling elegan, tetapi ini akan memperbaiki masalah Anda ...

SELECT a,string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b,d
FROM json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}')
AS x(a int, b text, d text);

Cara kerjanya cukup mudah:

Pertama , ambil textstring b, dan lepaskan ke informasi yang berguna. Ini dilakukan dengan menggunakan regexp_replace()sebagai

regexp_replace(b, '\[*\"*\s*\]*','','g')

untuk menghapus semua contoh [, ", ], dan setiap karakter spasi, atau lebih khusus, untuk menggantikan contoh-contoh dari karakter ini dengan '', dan untuk menerapkan ini secara global, ditandai dengan menggunakan bendera 'g'.

Selanjutnya , cukup pisahkan string ke array menggunakan string_to_array()as

string_to_array(your_string,',')

di mana dalam hal your_stringini hanyalah hasil di atas regexp_replace(). Argumen kedua ','menunjukkan string_to_array()bahwa item dipisahkan koma.

Ini akan menghasilkan text[]bidang yang berisi entri yang Anda inginkan.

Chris
sumber