The result from JSON_SEARCH() is not a valid JSON path. It's quoted, like a JSON string value. Notice the double-quotes:

mysql> select json_search(config, 'one', 'Infrastructure') 
  from table_config;
+----------------------------------------------+
| json_search(config, 'one', 'Infrastructure') |
+----------------------------------------------+
| "$.deploy[0]"                                |
+----------------------------------------------+

So if you try to use it as the path argument in JSON_SET(), it doesn't work:

mysql> select json_set(config, json_search(config, 'one', 'Infrastructure'), 'Infrastructure')
  from table_config;
ERROR 3143 (42000): Invalid JSON path expression. The error is around character position 1.

To use this as a JSON path, you have to remove those quotes:

mysql> select json_unquote(json_search(config, 'one', 'Infrastructure')) 
  from table_config;
+------------------------------------------------------------+
| json_unquote(json_search(config, 'one', 'Infrastructure')) |
+------------------------------------------------------------+
| $.deploy[0]                                                |
+------------------------------------------------------------+

Then you can use it in a call to JSON_SET():

mysql> select json_set(config, json_unquote(json_search(config, 'one', 'Infrastructure')), 'Infrastructure') 
  from table_config;
+------------------------------------------------------------------------------------------------+
| json_set(config, json_unquote(json_search(config, 'one', 'Infrastructure')), 'Infrastructure') |
+------------------------------------------------------------------------------------------------+
| {"deploy": ["Infrastructure", "API Security"], "operate": ["Pen Testing", "Bug Bounty"]}       |
+------------------------------------------------------------------------------------------------+
Answer from Bill Karwin on Stack Exchange
Top answer
1 of 1
5

The result from JSON_SEARCH() is not a valid JSON path. It's quoted, like a JSON string value. Notice the double-quotes:

mysql> select json_search(config, 'one', 'Infrastructure') 
  from table_config;
+----------------------------------------------+
| json_search(config, 'one', 'Infrastructure') |
+----------------------------------------------+
| "$.deploy[0]"                                |
+----------------------------------------------+

So if you try to use it as the path argument in JSON_SET(), it doesn't work:

mysql> select json_set(config, json_search(config, 'one', 'Infrastructure'), 'Infrastructure')
  from table_config;
ERROR 3143 (42000): Invalid JSON path expression. The error is around character position 1.

To use this as a JSON path, you have to remove those quotes:

mysql> select json_unquote(json_search(config, 'one', 'Infrastructure')) 
  from table_config;
+------------------------------------------------------------+
| json_unquote(json_search(config, 'one', 'Infrastructure')) |
+------------------------------------------------------------+
| $.deploy[0]                                                |
+------------------------------------------------------------+

Then you can use it in a call to JSON_SET():

mysql> select json_set(config, json_unquote(json_search(config, 'one', 'Infrastructure')), 'Infrastructure') 
  from table_config;
+------------------------------------------------------------------------------------------------+
| json_set(config, json_unquote(json_search(config, 'one', 'Infrastructure')), 'Infrastructure') |
+------------------------------------------------------------------------------------------------+
| {"deploy": ["Infrastructure", "API Security"], "operate": ["Pen Testing", "Bug Bounty"]}       |
+------------------------------------------------------------------------------------------------+
🌐
Database Guide
database.guide › json_replace-replace-values-in-a-json-document-in-mysql
JSON_REPLACE() – Replace Values in a JSON Document in MySQL
July 23, 2018 - SELECT JSON_REPLACE('{"Name": "Homer", "Age": 39}', '$.Gender', 'Male') AS 'Result'; ... +------------------------------+ | Result | +------------------------------+ | {"Age": 39, "Name": "Homer"} | +------------------------------+ Here’s an example using an array.
🌐
MySQL Tutorial
mysqltutorial.org › home › mysql json › mysql json_replace() function
MySQL JSON_REPLACE() Function
November 2, 2023 - You will learn how to use the MySQL JSON_REPLACE() function to replace existing values in a JSON document and return the updated document.
🌐
Sqliz
sqliz.com › mysql-ref › json_replace
MySQL JSON_REPLACE() Function
In MySQL, the JSON_REPLACE() function replaces existing data specified by the path in a JSON document and return the modified JSON document. Here is the syntax of the MySQL JSON_REPLACE() function: JSON_REPLACE(json, path, value[, path2, value2] ...)
🌐
Data and Open Source
ftisiot.net › mysqljson › how-to-edit-JSON-document-mysql
How to edit a JSON document in MySQL | Data and Open Source
To replace the second pizzaName from Margherita to Capricciosa you can · select JSON_SET(json_data,'$.pizzas[1].pizzaName','Capricciosa') from test; ... $.pizzas[1].pizzaName selects the pizzas item, the 2nd element in the array and the pizzaName subitem · the last parameter Capricciosa represents the value to replace
🌐
Stack Overflow
stackoverflow.com › questions › 43930364 › mysql-json-data-type-want-to-replace-multiple-array-json-value-i-e-update-the
php - Mysql JSON Data type : want to replace multiple array json value i.e update the record of nested json - Stack Overflow
May 12, 2017 - I want to update the record id=1 which has camp_id = 2 & update value of read_unread_status = 1 ... SELECT id,(SELECT json_search(access->'$[*].camp_id','all',2)) FROM access_record WHERE json_search(access->'$[*].camp_id','all',2) IS NOT NULL AND id = 1 ... Not entirely sure but try this, I will work on simple json but I have not try it on an array though.
🌐
MySQL
dev.mysql.com › doc › refman › 8.0 › en › json-modification-functions.html
MySQL :: MySQL 8.0 Reference Manual :: 14.17.4 Functions That Modify JSON Values
February 5, 2020 - The functions in this section modify JSON values and return the result. JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)
🌐
MySQL
dev.mysql.com › doc › refman › 9.6 › en › json.html
MySQL :: MySQL 9.6 Reference Manual :: 13.5 The JSON Data Type
For path syntax examples, see the descriptions of the various JSON functions that take paths as arguments, such as JSON_CONTAINS_PATH(), JSON_SET(), and JSON_REPLACE(). For examples which include the use of the * and ** wildcards, see the description of the JSON_SEARCH() function. MySQL also supports range notation for subsets of JSON arrays using the to keyword (such as $[2 to 10]), as well as the last keyword as a synonym for the rightmost element of an array. See Searching and Modifying JSON Values, for more information and examples.
Find elsewhere
Top answer
1 of 2
3

The functions you refer to all work exactly as expected and described in the manual; that is to say JSON_SET will insert or replace if a value already exists, JSON_INSERT will insert if a value doesn't already exist, and JSON_REPLACE will replace a pre-existing value. You can use JSON_ARRAY_INSERT and JSON_ARRAY_APPEND to more easily add values to a JSON array.

-- extract second element
select json_extract('["A", "B", "C"]', '$[1]')
-- "B"

-- replace second element
select json_set('["A", "B", "C"]', '$[1]', 'D')
-- ["A", "D", "C"]

-- insert fourth element
select json_set('["A", "B", "C"]', '$[3]', 'E')
-- ["A", "B", "C", "E"]

-- attempt to insert second element fails as it already exists
select json_insert('["A", "B", "C"]', '$[1]', 'F')
-- ["A", "B", "C"]

-- use json_array_insert to insert a new second element and move the other elements right
select json_array_insert('["A", "B", "C"]', '$[1]', 'F')
-- ["A", "F", "B", "C"]

-- insert fourth element
select json_insert('["A", "B", "C"]', '$[3]', 'F')
-- ["A", "B", "C", "F"]

-- or use json_array_append to add an element at the end
select json_array_append('["A", "B", "C"]', '$', 'F')
-- ["A", "B", "C", "F"]

-- replace second element
select json_replace('["A", "B", "C"]', '$[1]', 'G')
-- ["A", "G", "C"]

-- attempt to replace non-existing element fails
select json_replace('["A", "B", "C"]', '$[3]', 'G')
-- ["A", "B", "C"]

Demo on dbfiddle

To use these functions on a column in a table, simply replace the ["A", "B", "C"] in the above calls with the column name, for example:

create table test (j json);
insert into test values ('["A", "B", "C"]');
select json_array_insert(j, '$[1]', 'F') 
from test
-- ["A", "F", "B", "C"]

Demo on dbfiddle

2 of 2
0

i think found the solution

for json array, it's not possible to use JSON_EXTRACT, JSON_SET, JSON_REPLACE, JSON_INSERT by array values, and you have to know the place of each value in json array (in my opinion it's a weakness).

for example to select 2nd value you can use $[1], but for insert values you can use JSON_ARRAY_APPENDand JSON_ARRAY_INSERT

Top answer
1 of 2
1

Currently, it's complicated to look up numerical values with MySQL JSON functions. In a JSON like the following, it would be simple:

{"id": "222", "active": 1}

There are many ways to get what you need, I present one that can give you ideas (modify everything that is necessary):

UPDATE `objects`
SET `objects`.`content` = 
  JSON_REPLACE(`objects`.`content`, CONCAT('$.data',
  (SELECT
    JSON_UNQUOTE(
      REPLACE(
        JSON_SEARCH(
          REPLACE(
            REPLACE(
              REPLACE(
                `der`.`content` ->> '$.data[*].id',
                ', ',
                '","'),
              ']',
              '"]'),
          '[',
          '["'),
        'one',
        '222'),
      '$',
      '')
    )
  FROM (SELECT `objects`.`content`
        FROM `objects`
        WHERE `objects`.`id` = 7383) `der`
  ), '.active'), 0)
WHERE `objects`.`id` = 7383;

Beware of possible performance problems.

See dbfiddle.

In the most recent version of MySQL (>= 8.0.4), the sentence would be much simpler:

UPDATE `objects`
  INNER JOIN JSON_TABLE(
    `objects`.`content`,
    '$.data[*]' COLUMNS(
      `rowid` FOR ORDINALITY,
      `id` INT PATH '$.id'
    )
  ) `der` ON `der`.`id` = 222
SET `objects`.`content` =
  JSON_REPLACE(
    `objects`.`content`,
    CONCAT('$.data[', `der`.`rowid` - 1, '].active'),
    0)
WHERE
  `objects`.`id` = 7383;

See db-fiddle.

2 of 2
0

It can be achieved by combining the functions JSON_SEARCH, which returns a dirty json path to the item you need, and then, extract the value of the jsonpath with an array index, concatenate it with subpath we want to update and use JSON_SET to set a new value to the final json path (tested with MySQL 5.7.32):

-- INPUT ------------------------------------------------
-- unique value for an object in the array
SET @unique_value = "12345";

-- object field we want to update
SET @field_to_update = '.myField';

-- new value
SET @new_value = 1;

-- PROCESSING ------------------------------------------
-- Get json path to the item with specified @unique_value
-- RESULT: $.data[6].id
SET @temp_path = ( TRIM(BOTH '"' FROM ( SELECT JSON_SEARCH(json, 'one', @unique_value, NULL, "$.data")
FROM `my-table`
WHERE `column1` = "abcd" ) ));

-- We are looking for the bracket that delimits index within the array of documents: [11]
SET @closing_bracket_index = (SELECT LOCATE(']', @temp_path));

-- Get json path with index of an object for @unique_value
-- in MySQL, string indexing starts from position 1, not a zero
-- RESULT: $.data[6]
SET @item_path = ( SELECT SUBSTRING(@temp_path, 1, @closing_bracket_index) );

-- $.data[6].myFIeld
SET @item_path_to_update = ( SELECT CONCAT(@item_path, @field_to_update) );

-- UPDATE JSON STATEMENT
UPDATE `my-table`
SET json = JSON_SET(json-column, @item_path_to_update, @new_value)
WHERE `column1` = "abcd";
🌐
MySQL
dev.mysql.com › doc › refman › 5.7 › en › json-modification-functions.html
MySQL :: MySQL 5.7 Reference Manual :: 12.17.4 Functions That Modify JSON Values
March 18, 2019 - If the existing value is not an array, it is autowrapped as an array, then extended with the new value. Otherwise, a path-value pair for a nonexisting path in the document is ignored and has no effect. For a comparison of JSON_INSERT(), JSON_REPLACE(), and JSON_SET(), see the discussion of ...
🌐
MySQL
dev.mysql.com › doc › refman › 9.6 › en › json-modification-functions.html
MySQL :: MySQL 9.6 Reference Manual :: 14.17.4 Functions That Modify JSON Values
The functions in this section modify JSON values and return the result. JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)
🌐
jOOQ
jooq.org › doc › latest › manual › sql-building › column-expressions › json-functions › json-replace-function
JSON_REPLACE
+--------------+--------------+ | json_replace | json_replace | +--------------+--------------+ | {"a":2} | {"a":1} | +--------------+--------------+ ... CASE WHEN coalesce( json_query('{"a":1}', '$.a'), json_value('{"a":1}', '$.a') ) IS NULL THEN '{"a":1}' ELSE json_modify( json_modify('{"a":1}', '$.a', ''), ('strict ' + '$.a'), 2 ) END
🌐
MySQL
dev.mysql.com › worklog › task
MySQL :: WL#8963: Support for partial update of JSON in the optimizer
For example: col = JSON_SET(JSON_REPLACE(col, ...), ...). The update is performed as a partial update only if all the changes are replacing an existing value with a new one (not adding new elements to the parent object or array), and there is a "hole" big enough to write the new value where ...
🌐
MySQL
dev.mysql.com › doc › refman › 8.4 › en › json-modification-functions.html
MySQL :: MySQL 8.4 Reference Manual :: 14.17.4 Functions That Modify JSON Values
The functions in this section modify JSON values and return the result. JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)