কীভাবে জসন অ্যারে পোস্টগ্রিস অ্যারে রূপান্তর করবেন?


69

আমার কাছে একটি কলাম dataরয়েছে যা একটি jsonদস্তাবেজকে মোটামুটি এভাবে ধারণ করে :

{
    "name": "foo",
    "tags": ["foo", "bar"]
}

আমি নেস্টেড tagsঅ্যারেগুলিকে কনটেনটেটেড স্ট্রিং ( foo, bar) এ পরিণত করতে চাই । array_to_string()তাত্ত্বিকভাবে ফাংশন দিয়ে এটি সহজেই সম্ভব হবে । তবে এই ফাংশনটি jsonঅ্যারেগুলিতে কাজ করে না । সুতরাং আমি অবাক হয়ে কীভাবে এই jsonঅ্যারেটিকে পোস্টগ্রিসে পরিণত করব array?


আপনি json_extract_path_text(your_column, 'tags') কি খুঁজছেন?
a_horse_with_no_name

1
@ a_horse_with_no_name: অবশিষ্ট সমস্যা: অ্যারে উপাদানগুলি এখনও JSON ফর্ম্যাটের জন্য উদ্ধৃত করা হয়েছে। পাঠ্যটি যথাযথভাবে তোলা যায় নি ...
এরউইন ব্র্যান্ডসেটেটার

উত্তর:


94

9.4 বা আরও নতুন পোস্টগ্রেস

স্পষ্টতই এই পোস্টটি দ্বারা অনুপ্রাণিত , Postgres 9.4 অনুপস্থিত ফাংশন (গুলি) যুক্ত করেছে:
প্যাচের জন্য লরেন্স রো এবং অ্যান্ড্রু ডানস্তানকে প্রতিশ্রুতিবদ্ধ করার জন্য ধন্যবাদ!

জেএসওন অ্যারে আনইস্ট করা। তারপরে এটি থেকে পোস্টগ্রিস অ্যারে তৈরি করতে array_agg()বা কোনও এআরএই নির্মাণকারী ব্যবহার করুন । বা একটি স্ট্রিং তৈরি করতে ।string_agg()text

একটি LATERALবা সম্পর্কযুক্ত সাবকোয়রিতে প্রতি সারিতে সামগ্রিক নিরীক্ষণ করা উপাদান । তারপরে মূল ক্রম সংরক্ষণ করা আছে এবং আমাদের প্রয়োজন নেই ORDER BY, GROUP BYএমনকি বাইরের ক্যোয়ারিতে একটি অনন্য কীও নেই। দেখা:

jsonbনিম্নলিখিত সমস্ত এসকিউএল কোডের জন্য 'জসন' এর সাথে 'জসনব' প্রতিস্থাপন করুন ।

SELECT t.tbl_id, d.list
FROM   tbl t
CROSS  JOIN LATERAL (
   SELECT string_agg(d.elem::text, ', ') AS list
   FROM   json_array_elements_text(t.data->'tags') AS d(elem)
   ) d;

সংক্ষিপ্ত বাক্য গঠন:

SELECT t.tbl_id, d.list
FROM   tbl t, LATERAL (
   SELECT string_agg(value::text, ', ') AS list
   FROM   json_array_elements_text(t.data->'tags')  -- col name default: "value"
   ) d;

সম্পর্কিত:

সম্পর্কযুক্ত subquery এ আররে নির্মাণকারক:

SELECT tbl_id, ARRAY(SELECT json_array_elements_text(t.data->'tags')) AS txt_arr
FROM   tbl t;

সম্পর্কিত:

সূক্ষ্ম পার্থক্য : nullউপাদানগুলি প্রকৃত অ্যারেগুলিতে সংরক্ষিত থাকে । উপরের প্রশ্নগুলিতে একটি textস্ট্রিং উত্পাদন করা সম্ভব নয়, এতে nullমান থাকতে পারে না । সত্য উপস্থাপনা একটি অ্যারে।

ফাংশন মোড়ক

বারবার ব্যবহারের জন্য, এটিকে আরও সহজ করে তোলার জন্য, কোনও ক্রিয়ায় যুক্তিকে আবদ্ধ করুন:

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

এটি একটি এসকিউএল ফাংশন করুন , যাতে এটি আরও বড় ক্যোয়ারিতে ইনলাইন করা যায়। বড় প্রশ্নগুলিতে পুনরাবৃত্তি মূল্যায়ন এড়াতে এবং সূচক এক্সপ্রেশনগুলিতে এটির অনুমতি দেওয়ার জন্য এটি
তৈরি করুন IMMUTABLE(কারণ এটি।

কল করুন:

SELECT tbl_id, json_arr2text_arr(data->'tags')
FROM   tbl;

ডিবি <> ফিডল এখানে


9.3 বা তার বেশি বয়সীদের পোস্টগ্র্যাগ করে

ফাংশনটি ব্যবহার করুন json_array_elements()। তবে আমরা এটি থেকে ডাবল উদ্ধৃত স্ট্রিংগুলি পাই ।

বহির্মুখী ক্যোয়ারিতে সমষ্টি সহ বিকল্প জিজ্ঞাসা। CROSS JOINনিখোঁজ বা খালি অ্যারে সহ সারিগুলি সরিয়ে দেয়। প্রক্রিয়াজাতকরণ উপাদানগুলির জন্যও কার্যকর হতে পারে। আমাদের একত্রিত করার জন্য একটি অনন্য কী প্রয়োজন:

SELECT t.tbl_id, string_agg(d.elem::text, ', ') AS list
FROM   tbl t
CROSS  JOIN LATERAL json_array_elements(t.data->'tags') AS d(elem)
GROUP  BY t.tbl_id;

ARRAY নির্মাতা, এখনও উদ্ধৃত স্ট্রিং সহ:

SELECT tbl_id, ARRAY(SELECT json_array_elements(t.data->'tags')) AS quoted_txt_arr
FROM   tbl t;

নোট যে nullউপরে উল্লিখিত নয়, টেক্সট মান "নাল" রূপান্তরিত হয়। ভুল, কঠোরভাবে কথা বলা এবং সম্ভাব্য অস্পষ্ট

দরিদ্র ব্যক্তির সাথে উদ্বিগ্ন trim():

SELECT t.tbl_id, string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM   tbl t, json_array_elements(t.data->'tags') d(elem)
GROUP  BY 1;

টিবিএল থেকে একটি একক সারি পুনরুদ্ধার করুন:

SELECT string_agg(trim(d.elem::text, '"'), ', ') AS list
FROM   tbl t, json_array_elements(t.data->'tags') d(elem)
WHERE  t.tbl_id = 1;

স্ট্রিংগুলি সহ সম্পর্কিত সাবকোয়ারি ফর্মগুলি:

SELECT tbl_id, (SELECT string_agg(trim(value::text, '"'), ', ')
                FROM   json_array_elements(t.data->'tags')) AS list
FROM   tbl t;

অ্যারে নির্মাণকারী:

SELECT tbl_id, ARRAY(SELECT trim(value::text, '"')
                     FROM   json_array_elements(t.data->'tags')) AS txt_arr
FROM   tbl t;

আসল (পুরানো) এসকিউএল ফিডল
ডিবি <> ফিডল এখানে।

সম্পর্কিত:

নোটস (পৃষ্ঠা 9.4 এর পরে পুরানো)

JSON অ্যারে থেকে যথাযথ মানগুলি ফিরিয়ে json_array_elements_text(json)আনতে আমাদের দুটি, দুটিয়ের দরকার হবে । তবে মনে হচ্ছে এটি জেএসএন কার্যাদি সরবরাহিত অস্ত্রাগার থেকে অনুপস্থিত । বা স্কেলারের মান থেকে কোনও মান বের করতে অন্য কোনও ফাংশন । আমিও সেটিকে মিস করছি বলে মনে হচ্ছে। তাই আমি ইম্প্রোমাইজ করেছি , তবে তা তুচ্ছ-মামুলির ক্ষেত্রে ব্যর্থ হবে ...json_array_elements(json)texttextJSON
trim()


সর্বদা ভালো পোস্ট, তবে আপনার অভ্যন্তরীণ সম্পর্কে আপনার জ্ঞানের সাথে কেন অ্যারে-> জসোনব থেকে নিক্ষেপ করা হচ্ছে না। আমি অন্য কাস্টটি বাস্তবায়িত করতে বুঝতে পারি না কারণ স্কুয়েল-অ্যারে আরও জোরালোভাবে টাইপ করা হয়। এটি কি কারণ পোস্টগ্র্রেএসকিউএল কাস্ট করার জন্য স্বয়ংক্রিয় উত্পন্ন কোড (ইন্টি [], বিগিন্ট [], পাঠ্য []) ইত্যাদি থেকে বিরত
ইভান ক্যারল

3
@ ইভান: আপনি to_jsonb()অ্যারে-> জসনব রূপান্তরের জন্য ব্যবহার করবেন।
এরউইন ব্র্যান্ডসেটেটার

না SELECT ARRAY(SELECT json_array_elements_text(_js))সত্যিই গ্যারান্টি দিই যে অ্যারের ক্রম সংরক্ষিত আছে? অপ্টিমাইজারটি কি json_array_elements_text থেকে সারিগুলির ক্রমটি তাত্ত্বিকভাবে পরিবর্তিত করার অনুমতি দিচ্ছে না?
ফেলিক্স জিসেন্ডারফার

@ ফেলিক্স: এসকিউএল স্ট্যান্ডার্ডে কোনও আনুষ্ঠানিক গ্যারান্টি নেই। (তারপরে আবার, সেট রিটার্নিং ফাংশনগুলি এমনকি স্ট্যান্ডার্ড এসকিউএল এর SELECT তালিকায় শুরু করার অনুমতি নেই)) তবে পোস্টগ্রিস ম্যানুয়ালটিতে একটি অনানুষ্ঠানিক দাবি রয়েছে। দেখুন: dba.stackexchange.com/a/185862/3684 সুস্পষ্ট হতে - একটি স্বল্প পারফরম্যান্স জরিমানার ব্যয়ে - দেখুন: dba.stackexchange.com/a/27287/3684 । ব্যক্তিগতভাবে, আমি 100% নিশ্চিত যে এই নির্দিষ্ট অভিব্যক্তি 9.4.4 সাল থেকে পোস্টগ্রিসের প্রতিটি বর্তমান এবং ভবিষ্যতের সংস্করণে প্রত্যাশা অনুযায়ী কাজ করে।
এরউইন ব্র্যান্ডসটেটার

@ এর্বিন ব্র্যান্ডসটেটার এটি নিশ্চিত করার জন্য আপনাকে অনেক ধন্যবাদ! আমি বর্তমানে নিবন্ধের জন্য কিছু গবেষণা করছি যা পোস্টগ্র্রেএসকিউএলএর দ্বারা সরবরাহিত গ্যারান্টি সরবরাহের আনুষ্ঠানিক এবং অনানুষ্ঠানিক গ্যারান্টির সংক্ষিপ্তসার এবং আপনার উত্তরগুলি অবিশ্বাস্যভাবে সহায়ক হয়েছে! আপনি যদি নিবন্ধটি পর্যালোচনা করতে আগ্রহী হন তবে আমাকে জানান, তবে তা না হলে কোনও উদ্বেগ নেই। আমি আপনার স্ট্যাকওভারফ্লো অবদানের জন্য অবিশ্বাস্যভাবে কৃতজ্ঞ এবং কয়েক বছর ধরে আপনার কাছ থেকে অনেক কিছু শিখেছি!
ফেলিক্স জিসেন্ডারফার

16

পিজি 9.4+

স্বীকৃত উত্তরটি অবশ্যই আপনার যা প্রয়োজন তা হ'ল, তবে সরলতার জন্য এখানে আমি এর জন্য ব্যবহারকারী একটি সহায়ক:

CREATE OR REPLACE FUNCTION jsonb_array_to_text_array(
  p_input jsonb
) RETURNS TEXT[] AS $BODY$

DECLARE v_output text[];

BEGIN

  SELECT array_agg(ary)::text[]
  INTO v_output
  FROM jsonb_array_elements_text(p_input) AS ary;

  RETURN v_output;

END;

$BODY$
LANGUAGE plpgsql VOLATILE;

তারপরে কেবল করুন:

SELECT jsonb_array_to_text_array('["a", "b", "c"]'::jsonb);

আমি আমার উত্তর এবং একটি সহজ ফাংশনে কিছু দ্রুত এক্সপ্রেশন যুক্ত করেছি। এটি যথেষ্ট পরিমাণে সস্তা হতে পারে।
এরউইন ব্র্যান্ডসটেটার

4
এই ফাংশনটি বিশুদ্ধ এসকিউএল হওয়া উচিত যাতে অপ্টিমাইজারটি এতে উঁকি দিতে পারে। এখানে pgplsql ব্যবহার করার দরকার নেই।
ভাগ

8

পোস্টগ্র্রেএসকিউএল মেলিং তালিকাগুলিতে এই প্রশ্নটি জিজ্ঞাসা করা হয়েছিল এবং আমি জেএসএন ফিল্ড এক্সট্রাকশন অপারেটরের মাধ্যমে পোস্টগ্র্রেএসকিউএল পাঠ্যের ধরণে জেএসএন পাঠ্য রূপান্তর করার এই হ্যাকিশ পদ্ধতি নিয়ে এসেছি:

CREATE FUNCTION json_text(json) RETURNS text IMMUTABLE LANGUAGE sql
AS $$ SELECT ('['||$1||']')::json->>0 $$;

db=# select json_text(json_array_elements('["hello",1.3,"\u2603"]'));
 json_text 
-----------
 hello
 1.3
 

মূলত এটি মানকে একটি একক-উপাদান অ্যারে রূপান্তর করে এবং তারপরে প্রথম উপাদানটির জন্য জিজ্ঞাসা করে।

আরেকটি পদ্ধতি হ'ল এই অপারেটরটি সমস্ত ক্ষেত্র এক-এক করে নিষ্কাশন করতে ব্যবহার করা। তবে বড় অ্যারেগুলির জন্য এটি সম্ভবত ধীরে ধীরে, কারণ এটি প্রতিটি অ্যারে উপাদানগুলির জন্য পুরো JSON স্ট্রিংকে পার্স করা দরকার, যা O (n ^ 2) জটিলতা তৈরি করে।

CREATE FUNCTION json_array_elements_text(json) RETURNS SETOF text IMMUTABLE LANGUAGE sql
AS $$ SELECT $1->>i FROM generate_series(0, json_array_length($1)-1) AS i $$;

db=# select json_array_elements_text('["hello",1.3,"\u2603"]');
 json_array_elements_text 
--------------------------
 hello
 1.3
 

1

আমি কয়েকটি বিকল্প পরীক্ষা করেছি। এখানে আমার প্রিয় ক্যোয়ারী। ধরুন আমাদের কাছে একটি টেবিল আছে যা আইডি এবং জসন ফিল্ডযুক্ত। জসন ফিল্ডে অ্যারে রয়েছে, যা আমরা পিজি অ্যারেতে রূপান্তর করতে চাই।

SELECT * 
FROM   test 
WHERE  TRANSLATE(jsonb::jsonb::text, '[]','{}')::INT[] 
       && ARRAY[1,2,3];

এটি অন্যদের তুলনায় যে কোনও জায়গায় এবং দ্রুত কাজ করছে, তবে ক্র্যাচযুক্ত দেখাচ্ছে)

প্রথমত json অ্যারে পাঠ্য হিসাবে কাস্ট করা হয় এবং তারপরে আমরা কেবল বর্গক্ষেত্র বন্ধনীতে স্কোয়ার বন্ধনী পরিবর্তন করি। অবশেষে পাঠ্যটি প্রয়োজনীয় ধরণের অ্যারে হিসাবে পোষ্ট করা হচ্ছে।

SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::INT[];

এবং যদি আপনি পাঠ্য [] অ্যারে পছন্দ করেন

SELECT TRANSLATE('[1]'::jsonb::text, '[]','{}')::TEXT[];

2
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"আমি মনে করি এটি কীভাবে কাজ করার কথা সে সম্পর্কে আপনাকে কিছু ব্যাখ্যা যোগ করতে হবে।
dezso

প্রশ্নটি কীভাবে JSON অ্যারে (!) কে পিগ অ্যারেতে পরিণত করবেন। ধরুন আমার কাছে আইডি এবং জসনব কলামযুক্ত টেবিল রয়েছে। জেএসএনবি কলামে জসন অ্যারে রয়েছে। তারপরে
ফিসিক্যালক্লিফ

অনুবাদ করুন (জসনব :: জসনব :: পাঠ্য, '[]', '{}') :: আইএনটি [] জসন অ্যারেটিকে পিগ অ্যারে রূপান্তর করে।
ফিসালক্লিফ

SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"এটি এত বোমা-প্রমাণ নয় ...
dezso

এই অ্যারেগুলির জন্য পাঠ্য [] ব্যবহারের বিষয়টি বিবেচনা করুন
ফিসিকালক্লিফ

0

এই প্রশ্নের উত্তর থেকে নেওয়া এই কয়েকটি ফাংশন হ'ল আমি কী ব্যবহার করছি এবং তারা দুর্দান্ত কাজ করছে

CREATE OR REPLACE FUNCTION json_array_casttext(json) RETURNS text[] AS $f$
    SELECT array_agg(x) || ARRAY[]::text[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION jsonb_array_casttext(jsonb) RETURNS text[] AS $f$
    SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION json_array_castint(json) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION jsonb_array_castint(jsonb) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

তাদের প্রত্যেকটিতে, একটি খালি অ্যারের সাথে একত্রিত হয়ে, তারা এমন একটি মামলা পরিচালনা করে যা আমাকে কিছুক্ষণের জন্য আমার মস্তিষ্ককে ধরে ফেলেছিল, যদি আপনি চেষ্টা করেন এবং json/ jsonbছাড়াই একটি খালি অ্যারে ফেলে দেন তবে আপনি কোনও পরিবর্তে কিছু পাবেন না খালি অ্যারে ( {}) হিসাবে আপনি আশা করবেন। আমি নিশ্চিত তাদের জন্য কিছু অপ্টিমাইজেশন রয়েছে, তবে ধারণাটি ব্যাখ্যা করার ক্ষেত্রে সরলতার জন্য এগুলি বাকি রয়েছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.