I have a mysql JSON column like:
column value
data [{ "report1": { "result": "5"}, "report2": {"result": "6"}, "report3": {"a": "4"}}, {"report1": { "result": "9"},"report4": {"details": "<b>We need to show the details here</b>"}, "report3": {"result": "5"}}]
another instance of data is:
[{ "report1": { "result": "5"}, "report2": {"result": "6"}, "report3": {"a": "4"}}, {"report1": { "result": "9"}, "report3": {"result": "5"},"report4": {"details": "<b>We need to show the details here</b>"}}]
In above record the key is present on 2nd index.
And in this:
[{ "report1": { "result": "5"}, "report2": {"result": "6"}, "report3": {"a": "4"}}, {"report1": { "result": "9"}, "report3": {"result": "5"}}]
The key is not present.
I need to replace {"details": "<b>We need to show the details here</b>"}, i.e. key report4's value with just [], I need now data in this report.
Actually, the logic for generating data have been changed from XML data to JSON for only that key, so, we need to replace it with a blank array, the target type now, without affecting the other data.
Is there any direct solution to that? I'm avoiding creating procedures here.
So, The Target data will be:
[{ "report1": { "result": "5"}, "report2": {"result": "6"}, "report3": {"a": "4"}}, {"report1": { "result": "9"},"report4": [], "report3": {"result": "5"}}]
And yes the keys in JSON are not consistent, means, a key may present in next or previous record in the table but may not present in this record.
The column should be of type JSON to use MySQL's JSON features efficiently. Then use the JSON modification functions, such as JSON_REPLACE.
Since each value contains a JSON array whose size may not be known in advance, you can create a small utility function to modify each element in the array.
create function modify_json(val json)
returns json
deterministic
begin
declare len int default json_length(val);
declare i int default 0;
while i < len do
# Replace the report4 property of the i'th element with an empty list
set val = json_replace(val, concat('$[', i, '].report4'), '[]');
set i = i + 1;
end while;
return val;
end;
With your utility function, update the records:
update table set data = modify_json(data)
where json_contains_path(data, 'one', '$[*].report4');
The records containing at least one element with a report4 property will be updated according to the modify_json function in this case. You could achieve the same thing with multiple update commands that operate on each index of the JSON array separately.
If the column can't be of type JSON for some reason, then you can allow MySQL to coerce the data or your program can marshall the string into a JSON object, modify the data, then serialize it to a string, and update the row.
Related
I'm trying to delete rows from a table depending on a specific value on a details column which is of json type.
The column is expected to have a json value like this one:
{
"tax": 0,
"note": "",
"items": [
{
"price": "100",
"quantity": "1",
"description": "Test"
}
]
}
The objects inside items could have a name entry or not. I'd like to delete those that don't have that entry.
NOTE: All objects inside items have the same entries so all of them will have or will not have the name entry
You can use a JSON path expression.
delete from the_table
where details::jsonb ## '$.items[*].name <> ""'
This checks if there is at least one array element where the name is not empty. Note that this wouldn't delete rows with an array element having "name": ""
As you didn't use the recommended jsonb type (which is the one that supports all the nifty JSON path operators), you need to cast the column to jsonb.
I have some data to be inserted into a MySQL column with the JSON datatype (blob_forms).
The value of the fields column is populated asynchronously, and if the document has multiple pages, then I need to append the data onto the existing row.
So a same table is;
document
document_id INT
text_data JSON
blob_forms JSON
blob_data JSON
The first chunk of data is correctly inserted and it is this data; (A sample)
{"fields": [
{"key": "Date", "value": "01/01/2020"},
{"key": "Number", "value": "xxx 2416 xx"},
{"key": "Invoice Date", "value": "xx/xx/2020"},
{"key": "Reg. No.", "value": "7575855"},
{"key": "VAT", "value": "1,000.00"}
]}
I am using lambda (Python) to handle the database insert, using this query
insertString = json.dumps(newObj)
sql = "INSERT INTO `document` (`document_id`, `blob_forms`) VALUES (%s, %s) ON DUPLICATE KEY UPDATE `blob_forms` = %s"
cursor.execute(sql, (self.documentId, insertString, insertString))
conn.commit()
The problem is, I also want to do an UPDATE too, so that if blob_forms has a value already, it would add the new items in the fields array to the existing objects fields array.
So basically use the original data input a second, so that if it is sent again, with the same document_id it would append to any existing data in blob_forms but preserve the JSON structure.
(Please note other processes write to this table and possibly this row due to the async nature, as the data for the columns can be written in any order, but the document_id ties them all together.
My failed attempt was something like this;
SET #j = {"fields": [{"key": "Date", "value": "01/01/2020"},{"key": "Number", "value": "xxx 2416 xx"},{"key": "Invoice Date", "value": "xx/xx/2020"},{"key": "Reg. No.", "value": "7575855"},{"key": "VAT", "value": "1,000.00"}]}
INSERT INTO `document` (`document_id`, `blob_forms`) VALUES ('DFGHJKfghj45678', #j) ON DUPLICATE KEY UPDATE blob_forms = JSON_INSERT(blob_forms, '$', #j)
I'm not sure that you can get the results that you want with 1 clean query in mysql. My advice would be to make the changes to the array on the client side (or wherever) and updating the entire field without delving into whether there is an existing value or not. I architect all of my api's in this way to keep the database interactions clean and fast.
So far this looks closest;
SET #j = '{"fields": [{"key": "Date", "value": "01/01/2020"},{"key": "Number", "value": "xxx 2416 xx"},{"key": "Invoice Date", "value": "xx/xx/2020"},{"key": "Reg. No.", "value": "7575855"},{"key": "VAT", "value": "1,000.00"}]}';
INSERT INTO `document` (`document_id`, `blob_forms`) VALUES ('DFGHJKfghj45678', #j) ON DUPLICATE KEY UPDATE blob_forms = JSON_MERGE_PRESERVE(blob_forms, #j)
{
"ID":0,
"OrganizationId":"",
"OrganizationName":"",
"Name":"",
"IsActive":"True",
"Type":2,
"AppliesTo":1,
"TagHOD":"",
"DisplayAsPrimary":"false",
"Values":[
]
}
Above is my json request which I have stored in a data file
Below is my json request body which I am getting after sending a parameter into it. It is sorted into alphabetical order which I don't want. I want the same order as above eg ID Should be first then OrganizationId
{
"AppliesTo": 1,
"DisplayAsPrimary": "false",
"ID": 0,
"IsActive": "True",
"Name": "TAG1205510333275",
"OrganizationId": 2404,
"OrganizationName": "",
"TagHOD": "",
"Type": 2,
"Values": [
{
"HODEmail": "tagsapiautomationae#mailinator.com",
"Id": 1,
"IsDeleted": false,
"Text": "Level20"
}
]
}
The JSON specification states: "An object is an unordered set of name/value pairs."
When working with JSON (and objects in most languages), the properties in objects are inherently unordered. You can't rely on different systems giving you the properties in the same order you supply them. In fact, you can't even rely on a single system giving you the properties in the same order all the time within a given execution of the code, even though many systems do behave that way.
If you want to preserve ordering, you either need to use an array to store the data, or you can use an array of object property names that stores the keys in the order you want, so you can use that array to reference them in the desired order later.
EG:
keyorder = ["ID",
"OrganizationId",
"OrganizationName",
"Name",
"IsActive",
"Type",
"AppliesTo",
"TagHOD",
"DisplayAsPrimary",
"Values"
]
You can then loop over this array when accessing elements in your object, so you are always accessing them in your defined order.
In python, with an object named "data" this would look like:
for key in keyorder:
print data.get(key)
Hi I'm trying to insert complex json data in mysql workbench but my json data being inserted alphabetically sorted. How do I get json data with same order which I passed in insert query?
Create table:
CREATE TABLE payload ( `id` INT NOT NULL,
`json` JSON NOT NULL,
PRIMARY KEY (`id`));
Insert Json
INSERT INTO payload ( id, json)
VALUES (2, '{
"request": "release",
"type": [
{
"type" : 1
}
],
"start": [
{
"type": "sample",
"id": "01",
"content": [
{
"name": "jon",
"email": "jon#gmail.com"
}
]
}
]
}');
stored json in database after select * table name:
'3', '{\"type\": [{\"type\": 1}], \"start\": [{\"id\": \"01\", \"type\": \"sample\", \"content\": [{\"name\": \"jon\", \"email\": \"jon#gmail.com\"}]}], \"request\": \"release\"}'
Actually I want to have store my json same as my inserted json in database.
Is there a way to prevent the json data being alphabetically sorted?
Thanks.
Mysql will automatically sort the keys of a JSON object before it's stored.
I had the same problem!
The solution is to change the column type to 'text' and then the order of keys will not be changed!
Use serialize before storing. The conversion will make the array unrecognizable to MySQL so when retrieved and restored with unserialize it will be in the exact same order as before storage.
The drawback is the native MySQL json functions and methods can't be used to search and manipulate the array. Serializing is good only for storing and retrieving.
The only other way is to add a key with a value representing the array's sort order. That drawback is that the array must be sorted to restore it to its original state.
I am trying to extract some data from a JSON field.
[{"id": 10001, "person1": {"name": "Kevin", "role": "junior"},
"person2": {"name": "Scott", "role": "senior"}}]
I am trying to extract the name and role under each ID.
I tried the below but it returned empty record.
SELECT json_extract_path(column_name::json,'person1','name') FROM table
The JSON you have shown is:
A list (as indicated by [])
That contains a dictionary
That contains a dictionary
You will first need to extract the first list element, then use the command you have supplied.
Try something like:
SELECT
json_extract_path(
json_extract_array_element_text(column_name::json, 0),
'person1',
'name'
)
FROM table