Project: YugabyteDB (App Definition and Development / Database)
File: jsonb-set-jsonb-insert.md

title: jsonbset() and jsonbinsert() headerTitle: jsonbset() and jsonbinsert() linkTitle: jsonbset() and jsonbinsert() description: Change a JSON value using jsonbset() and insert a value using jsonbinsert(). menu: v2.18: identifier: jsonb-set-jsonb-insert parent: json-functions-operators weight: 210 type: docs Purpose: Use `jsonbset()` to change a JSON value that is the value of an existing key-value pair in a JSON object or the value at an existing index in a JSON array. Use `jsonbinsert()` to insert a value, either as the value for a key that doesn't yet exist in a JSON object or beyond the end or before the start of the index range, for a JSON array. Signature: For `jsonb_set()`: ``` jsonb_in: jsonb path: text[] replacement: jsonb createifmissing: boolean default true return value: jsonb ``` Signature: For `jsonb_insert()`: ``` jsonb_in: jsonb path: text[] replacement: jsonb insert_after: boolean default false return value: jsonb ``` Notes: There is no `json` variant. It turns out that the effect of the two functions is the same in some cases. This brings useful "upsert" functionality when the target is a JSON array. The meaning of the defaulted `boolean` formal parameter is context dependent. The input JSON value must be either an object or an arrayin other words, it must have elements that can be addressed by a path. parsed, or when two JSON values are concatenated, and if a key is repeated, then the last-mentioned in left-to-right order wins.) The functionality is sufficiently illustrated by a "jsonin"_ value that has just primitive values. The result of each function invocation is the same. ```plpgsql do $body$ declare j constant jsonb := '{"a": 1, "b": 2, "c": 3}'; path constant text[] := array['d']; new_number constant jsonb := '4'; jset constant jsonb := jsonbset( jsonb_in => j, path => path, replacement => new_number, createifmissing => true); jinsert constant jsonb := jsonbinsert( jsonb_in => j, path => path, replacement => new_number, insert_after => false); expected_j constant jsonb := '{"a": 1, "b": 2, "c": 3, "d": 4}'; begin assert jset = expectedj and jinsert = expectedj, 'unexpected'; end; $body$; ``` Notice that the specified `path`, the key `"d"` doesn't yet exist. Each function call asks to produce the result that the key `"d"` should exist with the value `4`. So, as you see, the effect of each, as written above, is the same. If `jsonbset()` is invoked with "createifmissing" set to `FALSE`, then its result is the same as the input. But if `jsonbinsert()` is invoked with "insertafter" set to `TRUE`, then its output is the same as when it's invoked with "insertafter" set to `FALSE`. This reflects the fact that the order of key-value pairs in an object is insignificant. What if "path" specifies a key that does already exist? Now `jsonbinsert()` causes this error when it's invoked both with "insertafter" set to `TRUE` and with "insertafter"_ set to `FALSE`: ``` cannot replace existing key Try using the function jsonb_set to replace key value. ``` And this `DO` block quietly succeeds, both when it's invoked with "createifmissing" set to `FALSE` and when it's invoked with "createifmissing" set to

```plpgsql do $body$ declare j constant jsonb := '{"a": 1, "b": 2, "c": 3}'; path constant text[] := array['c']; new_number constant jsonb := '4'; jset constant jsonb := jsonbset( jsonb_in => j, path => path, replacement => new_number, createifmissing => true); expected_j constant jsonb := '{"a": 1, "b": 2, "c": 4}'; begin assert jset = expectedj, 'unexpected'; end; $body$; ``` A JSON array is a list of index-addressable valuesin other words, the order is defined and significant. Again, the functionality is sufficiently illustrated by a `jsonin` value that has just primitive values. Now the result of `jsonbset()` differs from that of `jsonb_insert()`. ```plpgsql do $body$ declare j constant jsonb := '["a", "b", "c", "d"]'; path constant text[] := array['3']; new_string constant jsonb := '"x"'; jset constant jsonb := jsonbset( jsonb_in => j, path => path, replacement => new_string, createifmissing => true); jinsert constant jsonb := jsonbinsert( jsonb_in => j, path => path, replacement => new_string, insert_after => true); expectedjset constant jsonb := '["a", "b", "c", "x"]'; expectedjinsert constant jsonb := '["a", "b", "c", "d", "x"]'; begin assert (jset = expectedj_set) and (jinsert = expectedj_insert), 'unexpected'; end; $body$; ``` Notice that the path denotes the fourth value and that this already exists. Here, `jsonbset()` located the fourth value and set it to "x" while `jsonbinsert()` located the fourth value and, as requested by "insertafter" set to `TRUE`, inserted "x" after it. Of course, with "insertafter" set to `FALSE`, "x" is inserted before "d". And (of course, again) the choice for "createifmissing" has no effect on the result of `jsonb_set()`. What if the path denotes a value beyond the end of the array? ```plpgsql do $body$ declare j constant jsonb := '["a", "b", "c", "d"]'; path constant text[] := array['42']; new_string constant jsonb := '"x"'; jset constant jsonb := jsonbset( jsonb_in => j, path => path, replacement => new_string, createifmissing => true); jinsert constant jsonb := jsonbinsert( jsonb_in => j, path => path, replacement => new_string, insert_after => true); expected_j constant jsonb := '["a", "b", "c", "d", "x"]'; begin assert jset = expectedj and jinsert = expectedj, 'unexpected'; end; $body$; ``` Here, each function had the same effect. The path, for `jsonbset()`, is taken to mean the as yet nonexistent fifth value. So, with "createifmissing" set to `FALSE`, `jsonbset()` has no effect. The path, for `jsonbinsert()`, is also taken to mean the as yet nonexistent fifth value. But now, the choice of `TRUE` or `FALSE` for "insertafter" makes no difference because before, or after, a nonexistent element is taken to mean insert it. Notice that if the path is specified as `-42` (i.e. an impossible array index) the result is to establish the specified value at the start of the array. `jsonbset` and `jsonbinsert` produce the same result, this: ```plpgsql do $body$ declare j constant jsonb := '["a", "b", "c", "d"]'; path constant text[] := array['-42']; new_string constant jsonb := '"x"'; jset constant jsonb := jsonbset( jsonb_in => j, path => path, replacement => new_string, createifmissing => true); jinsert constant jsonb := jsonbinsert( jsonb_in => j, path => path, replacement => new_string, insert_after => true); expected_j constant jsonb := '["x", "a", "b", "c", "d"]'; begin assert jset = expectedj and jinsert = expectedj, 'unexpected'; end; $body$; ``` The path, for `jsonbset()`, is taken to mean a new first value (implying that the existing values all move along one place). So, again, with "createifmissing" set to `FALSE`, `jsonbset()` has no effect. The path, for `jsonbinsert()`, is also taken to mean a new first value. So again, the choice of `TRUE` or `FALSE` for "insertafter" makes no difference because before or after, a nonexistent