পোস্টগ্রিস 9.4-এ JSONB প্রকারের কলামগুলিতে আপডেট অপারেশনগুলি কীভাবে সম্পাদন করা যায়


132

পোস্টগ্রিস 9.4 ডেটাটাইপ জেএসএনবি-র জন্য ডকুমেন্টেশনের সন্ধানে, কীভাবে জেএসএনবি কলামগুলিতে আপডেট করবেন তা আমার কাছে তাত্ক্ষণিকভাবে স্পষ্ট নয়।

জেএসওএনবির ধরণ এবং ফাংশনগুলির জন্য ডকুমেন্টেশন:

http://www.postgresql.org/docs/9.4/static/funifications-json.html http://www.postgresql.org/docs/9.4/static/datatype-json.html

উদাহরণ হিসাবে, আমার এই বেসিক টেবিল কাঠামোটি রয়েছে:

CREATE TABLE test(id serial, data jsonb);

সন্নিবেশ করা সহজ, যেমন:

INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');

এখন, আমি কীভাবে 'ডেটা' কলামটি আপডেট করব? এটি অবৈধ বাক্য গঠন:

UPDATE test SET data->'name' = 'my-other-name' WHERE id = 1;

এই নথিটি কোথাও কি স্পষ্ট যে আমি মিস করেছি? ধন্যবাদ।

উত্তর:


32

আদর্শভাবে, আপনি কাঠামোগত, নিয়মিত ডেটার জন্য আপনি JSON নথি ব্যবহার করেন না যা আপনি একটি সম্পর্কিত ডেটাবেসের অভ্যন্তরে ম্যানিপুলেট করতে চান। পরিবর্তে একটি সাধারণীকরণমূলক সম্পর্কিত ডিজাইন ব্যবহার করুন।

জেএসএন মূলত পুরো ডকুমেন্টগুলি সংরক্ষণের উদ্দেশ্যে যা আরডিবিএমএসের ভিতরে কারসাজি করার প্রয়োজন হয় না। সম্পর্কিত:

পোস্টগ্র্রেসে একটি সারি আপডেট করা সর্বদা পুরো সারির একটি নতুন সংস্করণ লেখায় । পোস্টগ্রিসের এমভিসিসি মডেলের এটিই মূল নীতি । পারফরম্যান্সের দৃষ্টিভঙ্গি থেকে, আপনি জেএসওএন অবজেক্টের ভিতরে কোনও একক টুকরো ডেটা পরিবর্তন করেছেন কিনা তা খুব কমই গুরুত্ব দেয়: সারিটির একটি নতুন সংস্করণ লিখতে হবে।

ম্যানুয়ালটিতে এইভাবে পরামর্শ :

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

এর সংক্ষিপ্তসার: একটি JSON অবজেক্টের ভিতরে যে কোনও কিছু সংশোধন করতে আপনাকে কলামে একটি পরিবর্তিত বস্তু নির্ধারণ করতে হবে। পোস্টগ্রিজ jsonএর সঞ্চয়স্থানের ক্ষমতা ছাড়াও ডেটা তৈরি এবং ম্যানিপুলেট করার জন্য সীমিত উপায় সরবরাহ করে। সংস্করণ 9.2 থেকে প্রতিটি নতুন প্রকাশের সাথে সরঞ্জামগুলির অস্ত্রাগার যথেষ্ট পরিমাণে বৃদ্ধি পেয়েছে। তবে মূল অবশেষ: আপনার সর্বদা কলামে একটি সম্পূর্ণ পরিবর্তিত বস্তু নির্ধারণ করতে হবে এবং পোস্টগ্র্রেস সর্বদা কোনও আপডেটের জন্য একটি নতুন সারি সংস্করণ লিখবে।

পোস্টগ্রিস 9.3 বা তার পরবর্তী সরঞ্জামগুলির সাথে কীভাবে কাজ করবেন তা কিছু কৌশল:

এই উত্তরটি তাই সব আমার অন্যান্য উত্তর হিসাবে অনেক downvotes যেমন সম্পর্কে আকৃষ্ট করেছে একসঙ্গে । লোকেরা ধারণাটি পছন্দ করে না বলে মনে হয়: অ-গতিশীল ডেটার জন্য একটি সাধারণ নকশাটি উন্নত। ক্রেগ রিঞ্জারের এই দুর্দান্ত ব্লগ পোস্টটি আরও বিশদে ব্যাখ্যা করেছে:


6
এই উত্তরটি কেবল JSON টাইপ নিয়ে উদ্বেগ প্রকাশ করে এবং JSONB উপেক্ষা করে।
ফায়াতজাফ

7
@ ফিয়াতজাফ: এই উত্তরটি ডেটা ধরণের jsonএবং jsonbএকই রকমের জন্য পুরোপুরি প্রযোজ্য । উভয়ই জেএসএন ডেটা সঞ্চয় করে, jsonbএটি কোনও সাধারণ বাইনারি আকারে করে যা এর কিছু সুবিধা (এবং কয়েকটি অসুবিধা) রয়েছে। stackoverflow.com/a/10560761/939860 আমরাও ডাটা টাইপ হচ্ছে জন্য ভাল সাধিত ডাটাবেসের ভিতরে অনেক। কোনও নথি প্রকার নয়। ভাল, এটি ছোট, কঠোরভাবে কাঠামোগত JSON নথির জন্য ঠিক fine তবে বড়, নেস্টেড ডকুমেন্টগুলি সেভাবে বোকামি হবে।
এরউইন ব্র্যান্ডসেটেটার

7
"পোস্টগ্রিস ৯.৩-এর সরঞ্জামগুলির সাথে কীভাবে কাজ করবেন নির্দেশাবলী" আপনার উত্তরটিতে প্রথম হওয়া উচিত যেমন এটি জিজ্ঞাসিত প্রশ্নের উত্তর দেয় .. কখনও কখনও এটি রক্ষণাবেক্ষণ / স্কিমা পরিবর্তন ইত্যাদির জন্য জেসন আপডেট করা এবং জেএসন ডন আপডেট না করার কারণগুলি বোধ করে সত্যিই প্রয়োগ করা হয়নি
মাইকেল ওয়াসার

22
এই উত্তর সহায়ক নয়, দুঃখিত। @ জভিউস, আপনি কি জিমোথির উত্তরটি গ্রহণ করতে চান না, কারণ এটি সত্যই আপনার প্রশ্নের উত্তর দেয়?
বাস্তিয়ান ভয়েগট

10
আপনার নিজের মন্তব্য / মতামত / আলোচনা যুক্ত করার আগে প্রথমে প্রশ্নের উত্তর দিন।
পিপিপি

330

আপনি যদি Postgresql 9.5 এ আপগ্রেড করতে সক্ষম হন jsonb_set, অন্যরা যেমন উল্লেখ করেছে তেমন কমান্ডটি উপলব্ধ।

নিম্নলিখিত প্রতিটি এসকিউএল বিবৃতিতে, আমি whereব্রেভিটির জন্য ধারাটি বাদ দিয়েছি ; স্পষ্টতই, আপনি এটি ফিরে যোগ করতে চাই।

আপডেট নাম:

UPDATE test SET data = jsonb_set(data, '{name}', '"my-other-name"');

ট্যাগগুলি প্রতিস্থাপন করুন (ট্যাগগুলি যুক্ত করতে বা অপসারণের বিরোধিতা হিসাবে):

UPDATE test SET data = jsonb_set(data, '{tags}', '["tag3", "tag4"]');

দ্বিতীয় ট্যাগটি প্রতিস্থাপন করা হচ্ছে (0-সূচিত):

UPDATE test SET data = jsonb_set(data, '{tags,1}', '"tag5"');

একটি ট্যাগ যুক্ত করুন ( এটি যতক্ষণ না 999 ট্যাগের চেয়ে কম ট্যাগ হিসাবে কাজ করবে; 999 থেকে 1000 বা তদূর্ধ্ব আর্গুমেন্ট একটি ত্রুটি তৈরি করে gene এটি পোস্টগ্রিস 9.5.3-এ আর দেখা যায় না; আরও বড় সূচক ব্যবহার করা যেতে পারে) :

UPDATE test SET data = jsonb_set(data, '{tags,999999999}', '"tag6"', true);

শেষ ট্যাগটি সরান:

UPDATE test SET data = data #- '{tags,-1}'

জটিল আপডেট (শেষ ট্যাগটি মুছুন, একটি নতুন ট্যাগ সন্নিবেশ করান, এবং নামটি পরিবর্তন করুন):

UPDATE test SET data = jsonb_set(
    jsonb_set(data #- '{tags,-1}', '{tags,999999999}', '"tag3"', true), 
    '{name}', '"my-other-name"');

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

জটিল উদাহরণে, তিনটি রূপান্তর এবং তিনটি অস্থায়ী সংস্করণ রয়েছে: প্রথমত, সর্বশেষ ট্যাগটি সরানো হয়েছে। তারপরে, নতুন ট্যাগ যুক্ত করে সেই সংস্করণটি রূপান্তরিত হবে। এরপরে, দ্বিতীয় সংস্করণটি nameক্ষেত্রটি পরিবর্তন করে রুপান্তরিত হবে । dataকলামের মান চূড়ান্ত সংস্করণ দিয়ে প্রতিস্থাপিত হয়।


42
ওপি যেমন অনুরোধ করেছে তেমন কোনও টেবিলের কলাম কীভাবে আপডেট করবেন তা দেখানোর জন্য আপনি বোনাস পয়েন্ট পাবেন
চাদরিক

1
@ চ্যাড্রিক: আমি আরও জটিল উদাহরণ যুক্ত করেছি। এটি আপনি যা অনুরোধ করেছেন ঠিক তেমন করে না, তবে এটি আপনাকে ধারণা দেয়। মনে রাখবেন যে বাইরের jsonb_setকলটিতে ইনপুট হ'ল অভ্যন্তরীণ কল থেকে আউটপুট এবং সেই অভ্যন্তরীণ কলটিতে ইনপুট ফলাফল data #- '{tags,-1}'। অর্থাৎ, সর্বশেষ ট্যাগ সহ মূল ডেটা সরানো হয়েছে।
জিমোথি

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

1
@ অ্যালেক্স: হ্যাঁ, কিছুটা হ্যাক। যদি আমি বলেছিলাম {tags,0}, এর অর্থ হবে "অ্যারের প্রথম উপাদান tags", আমাকে সেই উপাদানটিকে একটি নতুন মান দেওয়ার অনুমতি দেয়। 0 এর পরিবর্তে বড় সংখ্যা ব্যবহার করে অ্যারের মধ্যে বিদ্যমান উপাদানটির পরিবর্তে এটি অ্যারেতে একটি নতুন উপাদান যুক্ত করে। যাইহোক, যদি অ্যারেটিতে এটিতে 999,999,999 টিরও বেশি উপাদান থাকে তবে এটি একটি নতুন যুক্ত করার পরিবর্তে শেষ উপাদানটিকে প্রতিস্থাপন করবে।
জিমোথি

1
যদি ক্ষেত্রটি নাল থাকে তবে কি হবে? কাজ না দেখায়। যেমন তথ্য জসনব ক্ষেত্রটি শূন্য: "আপডেটের সংগঠক SET তথ্য = jsonb_set (তথ্য, '{দেশ}', '" এফআরএ "') যেখানে তথ্য - >> 'দেশ' :: পাঠ্যটি শূন্য রয়েছে;" আমি আপডেটের 105 টি রেকর্ড পাই তবে ডিবিতে কোনও পরিবর্তন নেই
স্ট্যাকডেভ

24

এটি 9.4 এ একটি বিদ্যমান এক্সটেনশন jsonbx এর উপর ভিত্তি করে অ্যান্ড্রু ডানস্তান দ্বারা jsonb_set আকারে আসছে যা 9.4 এর সাথে কাজ করে


এই লাইনের আর একটি সমস্যা হ'ল ব্যবহার jsonb_build_object(), কারণ x->key, কী-অবজেক্টের জুটি দেয় না, আপনার প্রয়োজনীয় জনসাধারণকে ফিরিয়ে দেয় jsonb_set(target, path, jsonb_build_object('key',x->key))
পিটার ক্রাউস

18

যারা এই সমস্যাটি নিয়ে চলেছেন এবং খুব দ্রুত সমাধান চান (এবং 9.4.5 বা তার আগে আটকে আছেন), আমি এখানে যা করেছি তা এখানে:

পরীক্ষার সারণী তৈরি

CREATE TABLE test(id serial, data jsonb);
INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');

জসনব সম্পত্তির নাম পরিবর্তন করতে বিবৃতি আপডেট করুন

UPDATE test 
SET data = replace(data::TEXT,'"name":','"my-other-name":')::jsonb 
WHERE id = 1;

শেষ পর্যন্ত, গৃহীত উত্তরটি সঠিক যে আপনি কোনও জসোনব অবজেক্টের পৃথক টুকরো (9.4.5 বা তার আগের) পরিবর্তন করতে পারবেন না; তবে, আপনি জেসনব অবজেক্টটিকে একটি স্ট্রিং (:: TEXT) এ কাস্ট করতে পারেন এবং তারপরে স্ট্রিংটি ম্যানিপুলেট করতে পারেন এবং জেসনব অবজেক্টে (:: jsonb) ফিরে যেতে পারেন।

দুটি গুরুত্বপূর্ণ ক্যাভেট রয়েছে

  1. এটি জসনের "নাম" নামক সমস্ত সম্পত্তি প্রতিস্থাপন করবে (ক্ষেত্রে একই নামের সাথে একাধিক সম্পত্তি রয়েছে)
  2. আপনি যদি 9.5 ব্যবহার করেন তবে এটি jsonb_set এর মতো দক্ষ নয়

এই বলেই, আমি এমন একটি পরিস্থিতি পেরিয়ে এসেছি যেখানে আমাকে জসনব অবজেক্টে সামগ্রীর জন্য স্কিমা আপডেট করতে হয়েছিল এবং আসল পোস্টারটি যা জিজ্ঞাসা করছিল ঠিক তা সম্পাদন করার এটি সহজতম উপায়।


1
শুভ প্রভু, আমি কীভাবে দুটি ঘন্টার মতো জসনবকে আপডেট করব তা সন্ধান করছিলাম যাতে আমি সমস্ত \u0000নাল অক্ষর প্রতিস্থাপন করতে পারি , উদাহরণস্বরূপ সম্পূর্ণ চিত্রটি দেখানো হয়েছে। এর জন্য ধন্যবাদ!
জোশুয়া রবিনসন

3
ভাল লাগছে! আপনার উদাহরণে প্রতিস্থাপনের জন্য দ্বিতীয় যুক্তিতে বিটিডব্লুতে কোলন এবং তৃতীয়টি অন্তর্ভুক্ত নয়। দেখে মনে হচ্ছে আপনার কলটি হওয়া উচিতreplace(data::TEXT, '"name":', '"my-other-name":')::jsonb
ডেভিডিকাস

আপনাকে ধন্যবাদ ডেভিডিকাস! খুব বিলম্বিত আপডেটের জন্য দুঃখিত, তবে আমি আপনাকে অন্যদের জন্য ভাগ করে নেওয়ার প্রশংসা করি!
চাদ ক্যাপ্রা

12

এই প্রশ্নটি পোস্টগ্রেস 9.4 এর প্রসঙ্গে জিজ্ঞাসা করা হয়েছিল, তবে এই প্রশ্নে আসা নতুন দর্শকদের সচেতন হওয়া উচিত 9.5 পোস্টগ্রেসে, উপ-নথি জেএসওএনবি ক্ষেত্রগুলিতে তৈরি / আপডেট / মুছুন ক্রিয়াকলাপগুলি ডেটাবেস দ্বারা স্থানীয়ভাবে সমর্থন করে, এক্সটেনশনের প্রয়োজন ছাড়াই ফাংশন।

দেখুন: জেএসওএনবি অপারেটর এবং ফাংশন সংশোধন করছে


7

'নাম' বৈশিষ্ট্য আপডেট করুন:

UPDATE test SET data=data||'{"name":"my-other-name"}' WHERE id = 1;

এবং যদি আপনি উদাহরণস্বরূপ 'নাম' এবং 'ট্যাগ' বৈশিষ্ট্যগুলি মুছতে চান:

UPDATE test SET data=data-'{"name","tags"}'::text[] WHERE id = 1;

5

আমি নিজের জন্য ছোট ফাংশন লিখেছিলাম যা পোস্টগ্রিস 9.4 এ পুনরাবৃত্তভাবে কাজ করে। আমারও একই সমস্যা ছিল (ভাল তারা Postgres 9.5-এ এই মাথা ব্যাথার কিছু সমাধান করেছেন)। যাইহোক এখানে ফাংশনটি রয়েছে (আমি আশা করি এটি আপনার পক্ষে ভাল কাজ করে):

CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
    result JSONB;
    v RECORD;
BEGIN
    IF jsonb_typeof(val2) = 'null'
    THEN 
        RETURN val1;
    END IF;

    result = val1;

    FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP

        IF jsonb_typeof(val2->v.key) = 'object'
            THEN
                result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
            ELSE
                result = result || jsonb_build_object(v.key, v.value);
        END IF;
    END LOOP;

    RETURN result;
END;
$$ LANGUAGE plpgsql;

নমুনা ব্যবহার এখানে:

select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
                            jsonb_update                             
---------------------------------------------------------------------
 {"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)

আপনি দেখতে পাচ্ছেন এটি গভীর নীচে বিশ্লেষণ করে এবং যেখানে প্রয়োজন সেখানে মানগুলি আপডেট / আপডেট করে।


এটি 9.4-এ কাজ করে না, কারণ jsonb_build_object9.5
গ্রেগ

@ গ্রেগ আপনি ঠিক বলেছেন, আমি এখনই পরীক্ষা করেছি এবং আমি এখন পোস্টগ্র্যাসকিউএল 9.5 চালাচ্ছি - এই কারণেই এটি কাজ করে। এটি নির্দেশ করার জন্য ধন্যবাদ - আমার সমাধান 9.4.4 এ কাজ করবে না।
জে রাকজকিউইচজ

4

হতে পারে: আপডেটের পরীক্ষা SET ডেটা = '"আমার-অন্যান্য-নাম"' :: :: জেসন WHERE আইডি = 1;

এটি আমার ক্ষেত্রে কাজ করেছে, যেখানে ডেটা একটি জসন টাইপ


1
আমার জন্য পোস্টগ্র্যাসক্লুয়েল 9.4.5 এও কাজ করেছেন। পুরো রেকর্ডটি নতুন করে লেখা হয়েছে যাতে একক ক্ষেত্রে এটিএম আপডেট করতে পারে না।
কমেন্ট করুন

2

ম্যাথিউস ডি অলিভিয়ারা পোস্টগ্রেস্কল-এ জেএসএন সিআরইউডি অপারেশনের জন্য কার্যকর ফাংশন তৈরি করেছে। Dire i নির্দেশিকা ব্যবহার করে সেগুলি আমদানি করা যায়। আপনার ডাটা টাইপ যদি jsonb হয় তবে ফাংশনগুলির jsonb কাঁটাচামচটি লক্ষ্য করুন।

9.3 জসন https://gist.github.com/matheusoliveira/9488951

9.4 জসনব https://gist.github.com/inindev/2219dff96851928c2282

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