How to use MySQL JSON_SET to a document with numeric key? - mysql

I have a json field name shipping_info in mysql table with the following sample data
{
"shipping": {
"0": {
"phone": "(222) 222-2222",
"address1": "streeta",
"address2": null,
"address3": null,
"attention": "company",
"phone_ext": null,
"postal_code": "91406",
"proper_city": "VAN NUYS",
"address_type": "u",
"city_or_town": "VAN NUYS",
"country_code": "US"
}
}
}
My goal is to update the value in this path shipping.0.address1.
This is my query so far, but it doesn't seem to work
UPDATE cart_items
SET shipping_info = JSON_SET(
shipping_info,
'$.shipping[0].address1', 'new value'
)
WHERE cart_item_id= 1;

I was able to get this working with the following query:
UPDATE cart_items
SET shipping_info = JSON_SET(
shipping_info,
'$.shipping."0".address1', 'new value'
)
WHERE cart_item_id= 1;
I'm posting this as an answer just in case someone will also encounter this same scenario.

Related

Unable to Update a data in a table in a required format

The data present inside i column currently
{
"email": "abc#gmail.com",
"shopNo": "195",
"pincode": "454001",
"address1": "195",
"address2": "Bhoj kaniya school dhar",
"landmark": "Bhojshala ",
"streetName": "Bhoj kaniya school dhar",
"dateOfBirth": "06-11-2002",
"creationDate": "2021-09-23",
"salesValuesOption": {
"Lotte": "100000",
"Parle": "100000",
"Nestle": "80000",
"Mondelez": "5000",
"Perfetti": "5000"
},
"whatsappMobileNumber": "XXXXXXXXXX"
}
The data need to be updated in the required format in the DB
{
"email": "abc#gmail.com",
"shopNo": "195",
"pincode": "454001",
"address1": "195",
"address2": "Bhoj kaniya school dhar",
"landmark": "Bhojshala ",
"streetName": "Bhoj kaniya school dhar",
"dateOfBirth": "06-11-2002",
"creationDate": "2021-09-23",
"salesValuesOption": {
"option1":"Lotte",
"value1":"100000",
"option2":"Parle",
"value2":"100000",
"option3":"Nestle",
"value1":"80000",
"Option4": "Mondelez",
"value4": "5000",
"option5": "Perfetti",
"value5": "5000"
},
"whatsappMobileNumber": "XXXXXXXXXX"
}
The data in the above tables is stored inside a column and will be stored in a column and i literally tried alot of things that are available online but not much help from them either
WITH cte AS (
SELECT id, JSON_MERGE_PRESERVE(
JSON_OBJECTAGG( CONCAT('option', jsontable.rowid),
jsontable.jsonkey ),
JSON_OBJECTAGG( CONCAT('value', jsontable.rowid),
JSON_EXTRACT(info->'$.salesValuesOption',
CONCAT('$.', jsontable.jsonkey)))) info
FROM test
CROSS JOIN JSON_TABLE(JSON_KEYS(info->'$.salesValuesOption'),
'$[*]' COLUMNS (rowid FOR ORDINALITY,
jsonkey VARCHAR(255) PATH '$')) jsontable
GROUP BY id )
UPDATE test t1
JOIN cte t2 USING (id)
SET t1.info = JSON_MERGE_PATCH(JSON_REMOVE(t1.info, '$.salesValuesOption'),
JSON_OBJECT('salesValuesOption', t2.info));
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=47f6dab8ac4d5119ec987901e33a359b

SQL OPENJSON is not returning the values from sub-arrays

I have a JSON file that is properly formatted according to the Microsoft ISJSON function. However, it refuses to return a value from the nested array.
Here is an excerpt from the JSON file.
I want to return the following fields: id, symbol, name, and price.
I can get the first three, but the price always shows up null in the SQL query results.
JSON FILE SNIPPET:
{
"status": {
"timestamp": "2021-01-06T07:14:42.132Z",
"error_code": 0,
"error_message": null,
"elapsed": 14,
"credit_count": 1,
"notice": null,
"total_count": 4180
},
"data": [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"num_market_pairs": 9772,
"date_added": "2013-04-28T00:00:00.000Z",
"tags": [
"mineable",
"pow",
"sha-256",
"store-of-value",
"state-channels"
],
"max_supply": 21000000,
"circulating_supply": 18592156,
"total_supply": 18592156,
"platform": null,
"cmc_rank": 1,
"last_updated": "2021-01-06T07:13:02.000Z",
"quote": {
"USD": {
"price": 36248.609255662224,
"volume_24h": 225452557837159.16,
"percent_change_1h": 2.74047145,
"percent_change_24h": 19.54362963,
"percent_change_7d": 29.31750604,
"market_cap": 673939798064.3159,
"last_updated": "2021-01-06T07:13:02.000Z"
}
}
}
Here is the SQL Query that I'm using:
DECLARE #JSON VARCHAR(MAX)
SELECT #JSON = BulkColumn
FROM OPENROWSET
(BULK 'C:\TSP\output.json', SINGLE_CLOB) AS j
Select iif(ISJSON(#JSON)=1,'YES','NO') JSON_OK
Select * FROM OPENJSON (#JSON, '$.data')
WITH (
id int
,symbol varchar(20)
,[name] varchar(50)
,price float '$.data.quote.USD[0]'
)
I've tried everything I can think of to get the price to appear, but I'm missing something as it's not cooperating. Also, I set the database compatibility level to 130 as I read that could be the problem.... Still no luck.
Any help would be much appreciated.
$.data.quote.USD is not an array, it's a set of properties. It's also already inside the $.data context so should not include data in its path. Try the following instead:
select *
from openjson(#JSON, '$.data') with
(
id int
,symbol varchar(20)
,[name] varchar(50)
,price float '$.quote.USD.price'
)

Convert MySQL query result to JSON

The project I'm working on requires to save all of the DB operations. So when there will be added new user I've to log the date, operation type like 'INSERT', 'UPDATE', 'DELETE' and all user data. The project is in the development phase so the columns in User table are changing.
This what I plan to do is to select the new user data from the Users table and insert them to UserLog table as a JSON column.
Is it possible to convert SELECT * FROM table_name to JSON format?
I know that there is a possibility to convert separated columns by JSON_OBJECT function, but as I mentioned above, the columns are floating so I would be forced to change the JSON_OBJECT names each time I change anything in the main table. And there are a lot of tables!
It should work like this:
CREATE TABLE Users (
id INT(1) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
firstName VARCHAR(30) NOT NULL,
lastName VARCHAR(30) NOT NULL,
email VARCHAR(50),
)
The query:
SELECT * FROM Users;
Should return:
[
{
"id": 1,
"firstName": "Lucas",
"lastName": "Smith",
"email": "lucas#def.com"
},
{
"id": 2,
"firstName": "Ben",
"lastName": "Kovalsky",
"email": "ben#def.com"
},
...
]
Is there a simple solution to solve this problem? If not, what is your strategy for logging DB operations?
I'm not up to date with MySQL as I switched over to PostgreSQL but I found that the recent MySQL, from version 8, supports JSON:
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'id', `id`,
'firstName', `firstName`,
'lastName', `lastName`,
'email', `email`
)
)
FROM Users;
should work.
Edit, sources:
https://dev.mysql.com/doc/refman/8.0/en/json.html#json-values
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_json-arrayagg
I know this is an old thread, but for anyone still facing this issue, there is a way to convert the result set into json without knowing the column names. The key is to get the names of the columns in a string like 'column_1', column_1, 'column_2', column_2, ... and then use this string in a prepared query.
SET #column_name_string_for_query = "";
SHOW COLUMNS
FROM your_table_name
WHERE #column_name_string_for_query := TRIM(", " FROM CONCAT("'", Field, "', ", Field, ", ", #column_name_string_for_query));
SET #query_string = concat("
SELECT JSON_ARRAYAGG(JSON_OBJECT(", #column_name_string_for_query, "))
FROM your_table_name"
);
PREPARE statement FROM #query_string;
EXECUTE statement;
DEALLOCATE PREPARE statement;
You could also get the column names from INFORMATION_SCHEMA.COLUMNS, but that only works for tables that are not temporary tables. The solution above works for both temporary tables and normal tables.
You could also save this as a stored procedure for ease of use.
Normally converting the output to JSON or any other format is a job for the programming language or your mySQL IDE, but there is a way also from mySQL.
https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-json-output.html
https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-json-wrapping.html
Directly from documentation:
MySQL localhost:33060+ ssl world_x JS > shell.options.set('resultFormat','json')
MySQL localhost:33060+ ssl world_x JS > session.sql("select * from city where countrycode='AUT'")
{
"ID": 1523,
"Name": "Wien",
"CountryCode": "AUT",
"District": "Wien",
"Info": {
"Population": 1608144
}
}
{
"ID": 1524,
"Name": "Graz",
"CountryCode": "AUT",
"District": "Steiermark",
"Info": {
"Population": 240967
}
}
{
"ID": 1525,
"Name": "Linz",
"CountryCode": "AUT",
"District": "North Austria",
"Info": {
"Population": 188022
}
}
{
"ID": 1526,
"Name": "Salzburg",
"CountryCode": "AUT",
"District": "Salzburg",
"Info": {
"Population": 144247
}
}
{
"ID": 1527,
"Name": "Innsbruck",
"CountryCode": "AUT",
"District": "Tiroli",
"Info": {
"Population": 111752
}
}
{
"ID": 1528,
"Name": "Klagenfurt",
"CountryCode": "AUT",
"District": "Kärnten",
"Info": {
"Population": 91141
}
}
6 rows in set (0.0031 sec)
Also, adding the JSON_OBJECT, that is available from 5.7+, see the answer here.
mysql> SELECT JSON_OBJECT('id', 87, 'name', 'carrot');
+-----------------------------------------+
| JSON_OBJECT('id', 87, 'name', 'carrot') |
+-----------------------------------------+
| {"id": 87, "name": "carrot"} |
+-----------------------------------------

mariadb json query to get parent keys of specific child value

I got clients with contracts stored in json format in a mariadb database (10.3.21).
The parent keys are id's of contract types, cb = checkbox if contract is checked (1) or not (0), p & pt are price related and not really relevant for my question.
The simplified json format is structured as follows:
{
"1": {
"cb": "0",
"p": "1",
"pt": "m"
},
"2": {
"cb": "1",
"p": "395",
"pt": "y"
},
"3": {
"cb": "0",
"p": "",
"pt": "m"
},
"7": {
"cb": "1",
"p": "120",
"pt": "m"
}
}
I can query the database so I can get results of all the companies that have a specific contract type.
SELECT
`id`
, `company`
FROM
`db`.`clients`
WHERE
JSON_VALUE(`contracts`, '$.2.cb')=1
But I want to query json so I get an array of parent keys where child key cb = 1.
So it would give ["2","7"] as result for this json.
I thought something in the line of following, but that's not working.
Getting an empty result set instead of what I hoped for.
SELECT
`id`
, `company`
, JSON_QUERY(`contracts`, '$') AS `contracttypes`
FROM
`db`.`clients`
WHERE
JSON_VALUE(`contracts`, '$.%.cb')=1
Can't find (yet) if wildcards in paths are possible and if so what the syntax should be, so I get the results I want.
Alternative approach
Tried alternative approach with better results, but not there yet.
SELECT
`id`
, `company`
, json_search(`contracts`,'all','1') AS `contracttypes`
FROM
`db`.`clients`
Results: ["$.1.p", "$.2.cb", "$.7.cb"]
The keys of the cb items are what I want, but the first key due to the p item is not wanted.
Trying to do json_search on key with value like following give null result.
json_search(`contracts`,'all','"cb":"1"')
/* or with curlies */
json_search(`contracts`,'all','{"cb":"1"}')
Try:
SELECT
REGEXP_REPLACE(
JSON_SEARCH(#`json`, 'all', '1', NULL, '$**.cb'),
'[$.]|[.cb]',
SPACE(0)
) `json_result`;
See dbfiddle.

Update string JSON with mySql query

I have this mySql (ver 5.7.14) fields.
id shop_name json_string
1 shop_1 [{"your_number": "2", "player_id": "6789" }, {"your_number": "3", "player_id": "9877" }, {"your_number": "4", "player_id": "132456" }]
2 shop_2 [{"your_number": "2", "player_id": "6789" }, {"your_number": "3", "player_id": "9877" }, {"your_number": "4", "player_id": "132456" }]
how can I update string based on id and JSON your_number?
For example I'd like remove your_number = 3 string where id = 2
Result:
id shop_name json_string
2 shop_2 [{"your_number": "2", "player_id": "6789" }, {"your_number": "4", "player_id": "132456" }]
thanks!
I tested this and it works:
UPDATE Shops
SET json_string = JSON_REMOVE(
json_string,
SUBSTRING_INDEX(
JSON_UNQUOTE(JSON_SEARCH(json_string, 'one', '3', null, '$[*].your_number')), '.', 1)
)
WHERE id = 2;
I have to comment that this does NOT make JSON seem like a good idea for your application.
If you have a requirement to manipulate JSON documents, it would be easier to store your database as a normalized set of tables.
CREATE TABLE Shops (
id INT PRIMARY KEY,
shop_name VARCHAR(10)
);
CREATE TABLE ShopPlayers (
shop_id INT NOT NULL,
your_number INT NOT NULL,
player_id INT NOT NULL,
PRIMARY KEY (shop_id, your_number)
);
Now you can remove a player with more straightforward SQL:
DELETE FROM ShopPlayers WHERE shop_id = 2 AND your_number = 3;
I've been watching questions about mysql and json on Stack Overflow for a while, and I have to say that in virtually all cases I've seen, it would be better if the tables were designed in a traditional way, according to rules of normalization. The SQL queries would be easier to write and easier to debug, they would run faster, and the database would store the data more efficiently.