MySQL json_search on numeric values - mysql

I've got a json list of objects like that
[{
"something": "bla",
"id": 2
}, {
"something": "yes",
"id": 1
}]
My id field is always a numeric value. But when I try to find id = 2, MySQL returns NULL
select
json_search(
json_extract(
'[{"something": "bla" ,"id": 2}, {"something": "yes","id": 1}]',
"$[*].id"
),
'one',
2
) as json_search;
json_search |
------------|
|
When I use a string as value in my json id object instead of a numeric value, I got a result with Index 0.
select
json_search(
json_extract(
'[{"something": "bla" ,"id": "2"}, {"something": "yes","id": 1}]',
"$[*].id"
),
'one',
"2"
) as json_search;
json_search |
------------|
"$[0]" |
I'm using MySQL 5.7.17
##version |
-----------|
5.7.17-log |
Is numeric search in json arrays not provided in MySQL?

You can try something complicated, not intuitive and possibly with performance problems, but it's an option:
mysql> SELECT JSON_SEARCH(
-> REPLACE(
-> REPLACE(
-> REPLACE(
-> JSON_EXTRACT('[
'> {"something": "bla" ,"id": 2},
'> {"something": "yes","id": 1}
'> ]', "$[*].id"),
-> ', ', '","'),
-> '[', '["'),
-> ']', '"]'),
-> 'one', '2') `json_search`;
+-------------+
| json_search |
+-------------+
| "$[0]" |
+-------------+
1 row in set (0.00 sec)

Although the JSON_EXTRACT function was returning [2, 1] and it was a valid JSON, if you search the documentation the JSON_SEARCH function is:
JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])
So, as I understood you can only work with STRING values, and not with numeric values. But one solution to your problem could be to use the JSON_CONTAINS function as it returns 1 or 0 if the numeric value exists or not.
select
json_contains(
json_extract(
'[{"something": "bla" ,"id": 2}, {"something": "yes","id": 1}]',
"$[*].id"
),
"2"
) as json_contains;
The only problem is that you could not get the path to the given value within the JSON document. Hope it helped.

Related

Mysql JSON_REMOVE Array Key and Value (MariaDB)

I have the following JSON in MariaDB/MySQL:
[{"uid": 5}, {"uid": 6}, {"uid": 7}]
user_pst_tb
------------------------------
pst_id | pst_liked_by
--------------------------
1 |[]
-------|----------------
. |[{"uid": 9}]
-------|----------------
. |[]
-------|----------------
29 |[]
-------|----------------
30 | [{"uid": 5}, {"uid": 6}, {"uid": 7}]
i want to use JSON_REMOVE or any method to remove {"uid": 6} alone on pst_id = 30, but i cannot find how to formulate the path. I thought of this:
UPDATE user_pst_tb
SET `pst_liked_by` = JSON_REMOVE(
`pst_liked_by`, JSON_UNQUOTE(
REPLACE(
JSON_SEARCH( `pst_liked_by`, 'one', '6', null, '$**.uid' )
, '.uid'
, ''
)
)
) WHERE pst_id = 30;
for some reason the MariaDB and MySQL docs does not have such examples. Any help is appreciated.
I have also tried:
UPDATE user_pst_tb SET `pst_liked_by`= JSON_REMOVE(`pst_liked_by`, JSON_UNQUOTE( JSON_SEARCH(`pst_liked_by`, 'one','{"uid": 6}') )) WHERE `pst_id` = 30;
The second query clears all the JSON data sadly
UPDATE 1 (some GOOD NEWS)
I have tried this
UPDATE user_pst_tb SET `pst_liked_by` =
JSON_REMOVE(`pst_liked_by`,JSON_UNQUOTE(JSON_search(`pst_liked_by`,
'one', '6'))) WHERE `pst_id` = 30;
Somehow working but it leaves some empty {} behind.
Example: [{"uid": 5}, {}, {"uid": 7}] any idea to remove the empty brackets will be great!!
I was assisted by #ypercubeᵀᴹ
The final query that worked is:
UPDATE nz_psts_01
SET `pst_liked_by` = JSON_REMOVE(
`pst_liked_by`, JSON_UNQUOTE(
REPLACE(
JSON_SEARCH( `pst_liked_by`, 'one', '6', null, '$**.uid' )
, '.uid'
, ''
)
)
) WHERE pst_id = 29
and JSON_SEARCH( `pst_liked_by`, 'one', '6', null, '$**.uid' ) is not null ;
Hope it can help someone

MySQL: Extract all Keys from a nested JSON String

In addition to this answer is it possible to extract nested keys in a simple way?
Example:
{
"a": value,
"b": {
"c": value
"d": {
"e": value
}
}
}
Expected output: ['a', 'b.c', 'b.d.e']
What I have tried:
SELECT
f.`id` AS `field_name`
FROM table t,
JSON_TABLE(
JSON_KEYS(t.`column`, '$.b'),
'$[*]' COLUMNS(
`id` VARCHAR(191) PATH '$'
)
) AS t
but that would only show me one of the nested keys and skip the outer
SELECT JSON_SEARCH(val, 'all', 'value') result
FROM test;
| result |
| :-------------------------- |
| ["$.a", "$.b.c", "$.b.d.e"] |
db<>fiddle here

MySQL Parse and Split JSON value

I have a column which contains a JSON value of different lengths
["The Cherries:2.50","Draw:3.25","Swansea Jacks:2.87"]
I want to split them and store into a JSON like so:
[
{
name: "The Cherries",
odds: 2.50
},
{
name: "Draw",
odds: 3.25
},
{
name: "Swansea",
odds: 2.87
},
]
What I did right now is looping and splitting them in the UI which to me is quite heavy for the client. I want to parse and split them all in a single query.
If you are running MySQL 8.0, you can use json_table() to split the original arrayto rows, and then build new objects and aggregate them with json_arrayagg().
We need a primary key column (or set of columns) so we can properly aggreate the generated rows, I assumed id:
select
t.id,
json_arrayagg(json_object(
'name', substring(j.val, 1, locate(':', j.val) - 1),
'odds', substring(j.val, locate(':', j.val) + 1)
)) new_js
from mytable t
cross join json_table(t.js, '$[*]' columns (val varchar(500) path '$')) as j
group by t.id
Demo on DB Fiddle
Sample data:
id | js
-: | :-------------------------------------------------------
1 | ["The Cherries:2.50", "Draw:3.25", "Swansea Jacks:2.87"]
Query results:
id | new_js
-: | :----------------------------------------------------------------------------------------------------------------------
1 | [{"name": "The Cherries", "odds": "2.50"}, {"name": "Draw", "odds": "3.25"}, {"name": "Swansea Jacks", "odds": "2.87"}]
You can use json_table to create rows from the json object.
Just replace table_name with your table name and json with the column that contains json
SELECT json_arrayagg(json_object('name',SUBSTRING_INDEX(person, ':', 1) ,'odds',SUBSTRING_INDEX(person, ':', -1) ))
FROM table_name,
JSON_TABLE(json, '$[*]' COLUMNS (person VARCHAR(40) PATH '$') people;
Here is a Db fiddle you can refer
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=801de9f067e89a48d45ef9a5bd2d094a

MySQL JSON: finding value of sibling element in sub-array

I have the following (pseudo)JSON in a type JSON (LONGTEXT) column in my MariaDB 10.2
{"order":
{"otherstuff":...},
{"dates":
[
{
"typeId":2,
"date":"2019-05-21 09:00:00"
},
{
"typeId":4,
"date":"2019-05-21 10:00:00"
}
]
}
}
What I need is the order's date while I know which type I need (4).
An order can have a number of dates identified by their typeId. typeId 4 is not always in second position.
SELECT JSON_UNQUOTE(JSON_SEARCH(`json`, 'one', 4, NULL, '$.dates[*].typeId'))
// gives me: $.dates[1].typeId
My first thought now was to REPLACE typeId with date, but that complains about mixed collations.
How would I (more elegantly) reference the 'date' value here?
Also, the query is supposed to be the expression of a GENERATED column in my table. Since date id4 is not necessarily there for every order, I tried this:
SELECT IF(4 IN (JSON_EXTRACT(json, '$.dates[*].typeId')), 'yes', 'no')
// above condition evaluates to [2, 4]
I have trimmed away '[' and ']' but then it only gives me a 'yes' if 4 is first in the array (is it an array?).
So (without brackets):
[4, 7] -> yes
[2, 4] -> no
I'm assuming this doesn't get recognized as an array of values but a string. Then why does it give me 'yes' if my needle is in first position?
Instead of yes and no I obviously want to use the date and NULL.
The MySQL JSON functions are quite new to me. So maybe someone could point me in the right direction?
Try:
Option 1:
SELECT
JSON_UNQUOTE(
JSON_EXTRACT(
`json`,
REPLACE(
JSON_UNQUOTE(
JSON_SEARCH(
`json`,
'one',
4,
NULL,
'$.order.dates[*].typeId'
)
),
'typeId',
'date'
)
)
) `date`;
Option 2:
SELECT
IF(
JSON_CONTAINS(
JSON_EXTRACT(
`json`,
'$.order.dates[*].typeId'
),
4
),
'yes',
'no'
) `exists`;
See dbfiddle.

MySQL select last key with value JSON

I have JSON like:
{"1": "6", "2": "10", "3": "12"}
And i would like to get LAST key and value using MySQL query to get output like:
3x12
3 is the last key, and 12 is the last key value...
Is there any MySQL query to do that? I know using reading whole MySQL filed value as posted above and then while loop and if key is last print its value and key...but if is possible in MySQL query to get this output?
I im using this php that reads MySQL field value and get last key and value...but i don't know how to do it in mysql:
$json = json_decode('{"1": "6", "2": "10", "3": "12"}', true);
$value = end($json);
$key = key($json);
echo 'KEY: '.$key.'...VALUE: '.$value;
You can try something like the following, adjust as necessary:
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.20 |
+-----------+
1 row in set (0.00 sec)
mysql> SET #`json` := '
'> {
'> "1": "6",
'> "2": "10",
'> "3": "12"
'> }
'> ';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT
-> CONCAT(
-> JSON_UNQUOTE(#`key`),
-> 'x',
-> JSON_UNQUOTE(
-> JSON_EXTRACT(#`json`,
-> CONCAT('$.', #`key`)
-> )
-> )
-> ) `value`
-> FROM (
-> SELECT #`key` := JSON_EXTRACT(
-> JSON_KEYS(#`json`),
-> CONCAT('$[', JSON_LENGTH(#`json`) - 1, ']')
-> )
-> ) `init`;
+-------+
| value |
+-------+
| 3x12 |
+-------+
1 row in set (0.00 sec)
See db-fiddle.