Wrap/Convert json object into array of objects MySQL - mysql

I have a column named data and I have to update its content from something like {} to [{}] for each record in table A, I tried to use JSON_ARRAY() but it gives me a quoted
["{\"something\": \"true\"}"]
but I'd like to have something like
[{ "something": "true" }]
How I do it now?
SELECT JSON_ARRAY(data) FROM A;
How should I update it either using JSON_SET() or UPDATE?

You need to use a path to get the data as JSON, rather than referring to the column by itself. The path $ means the top-level object.
update A
SET data = CASE
WHEN data IS NULL THEN '[]' -- NULL becomes empty array
WHEN LEFT(data, 1) = '[' THEN data -- leave existing array alone
ELSE JSON_ARRAY(data->"$") -- put object inside array
END
DEMO

Try using
SELECT JSON_ARRAY_AGG(JSON_OBJECT(data)) from A;

Related

Postgresql: How to get value in JSON where key LIKE?

I have a column in my table containing a JSON statuses_json:
{
"demoStatus" : "true",
"productionStatus": "false"
}
I would like to retrieve a value where the key is LIKE some string.
For example, if I pass in "demo", I want to retrieve the value for the key demoStatus.
Right now I am able to retrieve values when passing the exact key:
`statuses_json->>'productionStatus' = 'false' `;
Extract the keys and run a query on it:
select *
from json_object_keys('{
"demoStatus" : "true",
"productionStatus": "false"
}') k where k like '%demo%';
I don't have a new enough version of postgresql but jsonb_path_query looks interesting, too. Then used statuses_json->>(...) to extract the corresponding value(s).
select statuses_json from your_table
where statuses_json->>(
select prop
from json_object_keys(statuses_json) as prop
where prop like 'demo%'
) = 'false';

how do I update semi structured data in snowflake?

We store a fair amount of value/pairs in a json object within a snowflake column.
The quantity of value/pairs is not pre-defined (hence semi structured data)
What are my options to update one of the value pairs?
Am I supposed to extract the entire JSON, convert it to string, modify the string and update the object column entirely?
Or is there a nice little function where I could update just the pair(s) I want?
create or replace table TB as
select $1 TB_ID, parse_json($2) my_json
from values
(1, '{ "FruitShape":"Round", "FruitSize":55 } '),
(2, '{ "FruitShape":"Square" } '),
(3, '{ "FruitShape":"Oblong", "FruitSize":22, "FruitColor":"Chartreuse" })
;
This created 3 rows with up to 3 value/pairs per row.
Let's say I want to change the property on the first row from "round" to "square"
UPDATE TB
SET my_json = parse_json('{ "FruitShape":"square", "FruitSize":55 }')
WHERE TB_ID = 1;
Is this what I am supposed to do?
You should not try to update, just append a new row and then use a view to access the current values.
You can do it with a javascript UDF. For example:
create or replace function merge_objects("a" object, "b" object)
returns object
language javascript
as
$$
return {...a, ...b}
$$;
And call like this:
select merge_objects(
object_construct('a',1,'b',2),
object_construct('b',3,'c',4)
);
select merge_objects(
parse_json('{"a":1,"b":[1,2,3]}')::object,
parse_json('{"c":2,"b":[2,3,4]}')::object
);

JSON_REMOVE object in MySQL

I am trying to delete objects from my JSON array in MySQL.
I have a table called cart with two fields quote_id type int and items type json with the following row stored inside MySQL
quote_id: 0
items:
[
{
"a":42,
"b":"test4"
},
{
"a":32,
"b":"test3"
}
]
I am trying to create a query which would delete json objects from the json array. For example every
{
"a":32,
"b":"test3"
}
I have tried many queries. First I ended up with this:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3'))), items)
WHERE quote_id = 13392;
However it just deletes "b":"test3" from the second object and left the "a":32 in it and I need a query that would find the whole object and would delete it.
This is my second query:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_SEARCH(items, 'one', CAST('{"a": 32, "b": "test3"}' AS JSON))), items)
WHERE quote_id = 13392;
However I don't think the search on it works. I tried it without using the CAST()AS JSON, however it still did not work.
As I said I am pretty sure the problem is with the JSON_SEARCH, but maybe someone has the solution?
Thank you!
The JSON_SEARCH returns the path of the property, not the path to the object itself.
So you can use the following solution to get the object path with SUBSTR:
SELECT JSON_REMOVE(items,
SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), 1, LOCATE('.', JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')))-1)
) FROM cart
You can also use REGEXP_SUBSTR to get the object path:
SELECT JSON_REMOVE(items, REGEXP_SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), '^\\$\\[[0-9]+\\]'))
FROM cart
demo on dbfiddle.uk

MySQL interprets my JSON object as a string during an update

I have a nullable column with the JSON type:
CREATE TABLE mytable (mycolumn JSON);
What I want to do is track events in an array as they come and keep each event in the form of an object inside this array. The desired contents of mycolumn after three events have been pushed into the array would be:
[
{"product": ["book"], "subgenre": ["scifi"], "genre": ["fiction"]},
{"product": ["book"], "subgenre": ["space"], "genre": ["fiction"]},
{"product": ["book"], "genre": ["romance"]},
]
The shape of the objects are irrelevant and unknown (the above are just examples). The only known is that each event will be an object with at least one property. Wether that property is an array, object, scalar, string, or null is unknown.
The column will be null initially and my tests revealed that I need to coalesce it into an array or pushing into it will fail.
The closest I got to making this work was:
UPDATE
mytable
SET
mycolumn = JSON_ARRAY_APPEND (
COALESCE (mycolumn, '[]'),
'$',
(
'{"product": ["book"], "subgenre": ["scifi"], "genre": ["fiction"], "type": ["newrelease"]}'
)
);
The problem is that this query interprets the whole object as a string and I end up with an array of strings instead of an array of objects:
SELECT mycolumn FROM mytable;
[
"{\"product\":[\"book\"],\"subgenre\":[\"scifi\"],\"genre\":[\"fiction\"]}",
"{\"product\":[\"book\"],\"subgenre\":[\"space\"],\"genre\":[\"fiction\"]}",
"{\"product\":[\"book\"],\"genre\":[\"romance\"]}"
]
Looks to me like you want to use something like the JSON_MERGE_PRESERVE function, not JSON_ARRAY_APPEND function.
The latter evaluates the third argument as a value, it doesn't evaluate the third argument as a JSON document.
In the UPDATE statement shown, the spurious parens around the third argument (to JSON_ARRAY_APPEND) have no meaning. That third argument is just a value. The value is a long-ish string that looks like JSON, but in this context, it's just a string.
Reference: https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-array-append
My suggestion to testing and development of expressions... it is easier and faster to use SELECT statements. Once we have expressions that are returning the expected/desired results, then we can move the expression into an UPDATE statement.
cast('{"product": ["book"], "subgenre": ["scifi"], "genre": ["fiction"], "type": ["newrelease"]}' as json)
This is a similar question:
MySQL append json object to array of json objects

How to check if a certain string is contained within an array returned by JSON_QUERY

I'm trying to write a SQL statement that will parse some JSON and return only rows where one of the arrays in the JSON Object contains a given value.
Example JSON:
Object 1:
{
"Key1": ["item1", "item2", "item3"]
}
Object 2:
{
"Key1": ["item1", "item3"]
}
I would like to only return rows where JSON_QUERY(object, '$.Key1').Contains("item2") is true (in this example, Object 1).
Of course, this magical function 'Contains()' does not exist in tsql, and I can't find any documentation of a function that performs as I'd like.
EDIT:
My current solution (which I'm not very fond of and would like to replace) checks if the string literal '"item1"' is contained within the value returned by JSON_QUERY. I don't like this, because it's possible an entry in the array could have a value like '123123"item1"123123', and then the conditional would return true.
Christian,
Sounds to me like your SQL Query could use a where clause using a LIKE comparison on a column
WHERE col1 LIKE 'some%funky%string'
The % is a wildcard declaritive
You can use OPENJSON to get a derived result set out of a json list or array:
The followin query uses JSON_QUERY to retrieve the list of strings within Key1. This is passed as argument into OPENJSON to retrive the list of strings as derived table:
DECLARE #jsonTable TABLE(ID INT IDENTITY, JsonString NVARCHAR(MAX));
INSERT INTO #jsonTable VALUES
(N'{
"Key1": ["item1", "item2", "item3"]
}')
,(N'{
"Key1": ["item1", "item3"]
}');
DECLARE #LookFor NVARCHAR(100)='Item2'
SELECT jt.ID
,jt.JsonString
,A.value
FROM #jsonTable jt
OUTER APPLY OPENJSON(JSON_QUERY(jt.JsonString,N'$.Key1')) AS A
--WHERE A.value=#LookFor
Uncomment the final WHERE to reduce the list to the rows with a value of Item2 (as defined in the variable #LookFor).