0

In PostgreSQL, my column type is json , the data is json array like:

[{"attsId": "42a2ce04-52ab-4a3c-8dfb-98c3d14b307d", "planId": 46, "filePath": "fileOperate\\upload", "cfileName": "潜在客户名单 (1).xls", "ufileName": "42a2ce04-52ab-4a3c-8dfb-98c3d14b307d.xls"}, {"attsId": "1adb2f13-00b0-4780-ae76-7a068dc3289c", "planId": 46, "filePath": "fileOperate\\upload", "cfileName": "潜在客户名单.xls", "ufileName": "1adb2f13-00b0-4780-ae76-7a068dc3289c.xls"}, {"attsid": "452f6c62-28df-47c7-8c30-038339f7b223", "planid": 48.0, "filepath": "fileoperate\\upload", "cfilename": "技术市场印花税.xls", "ufilename": "452f6c62-28df-47c7-8c30-038339f7b223.xls"}]

i want update one of the array date like:

UPDATE plan_base set atts->1='{"planId":"71"}' where id= 46;

how to do it? help me please

Meng Qian
  • 97
  • 1
  • 1
  • 9

1 Answers1

1

Here are two helper functions, to achieve your goal (requires PostgreSQL 9.3+):

This one can be used like UPDATEs (only updates an index, if it's already exists):

CREATE OR REPLACE FUNCTION "json_array_update_index"(
  "json"            json,
  "index_to_update" INTEGER,
  "value_to_update" anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('[', string_agg("element"::text, ','), ']')::json
  FROM (SELECT CASE row_number() OVER () - 1
                 WHEN "index_to_update" THEN to_json("value_to_update")
                 ELSE "element"
               END "element"
          FROM json_array_elements("json") AS "element") AS "elements"
$function$;

This one can be used, like an UPSERT (updates an index, if it exists, or creates, if not -- using some default value to fill up unused indexes):

CREATE OR REPLACE FUNCTION "json_array_set_index"(
  "json"            json,
  "index_to_set"    INTEGER,
  "value_to_set"    anyelement,
  "default_to_fill" json        DEFAULT 'null'
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('[', string_agg((CASE "index"
                                 WHEN "index_to_set" THEN to_json("value_to_set")
                                 ELSE COALESCE("json" -> "index", "default_to_fill")
                               END)::text, ','), ']')::json
  FROM generate_series(0, GREATEST("index_to_set", json_array_length("json") - 1)) AS "index"
$function$;

With these, you can UPDATE any json data, like:

UPDATE plan_base
SET    atts = json_array_update_index(atts, 1, '{"planId":"71"}'::json)
WHERE  id = 46;

Important! Json arrays are indexed from 0 (unlike other PostgreSQL arrays). My functions respect this kind of indexing.

SQLFiddle

More about updating a JSON object:

Update: functions are now compacted.

Community
  • 1
  • 1
pozs
  • 34,608
  • 5
  • 57
  • 63
  • I want to change the type 'json' to 'jsonb' how to do it,I tried and failed, can you help me – Meng Qian Feb 04 '15 at 02:02
  • pozs!!!Can you provide such a function like this:my jsonb array data is [{"attsId": "42a2ce04-52ab-4a3c-8dfb-98c3d14b307d", "planId": 46, "filePath": "fileOperate\\upload", "cfileName": "潜在客户名单 (1).xls", "ufileName": "42a2ce04-52ab-4a3c-8dfb-98c3d14b307d.xls"}],now i want loop the items and use key to update or find the item,can you help me Realization it,,,, – Meng Qian Feb 04 '15 at 02:27
  • @MengQian from `json` to `jsonb`: within this function? Just change the types & casts. Or within a table's column? http://stackoverflow.com/questions/28202158/postgresql-migrating-json-to-jsonb – pozs Feb 04 '15 at 09:19
  • @MengQian you can expand your json array with `json_array_elements()` -- you can find many examples with it here (in SO) too (f.ex. my first function in this answer). If you have a specific problem, you can post it as a new question. – pozs Feb 04 '15 at 09:24