PostgreSQL Get by name and not array - json

I have a column named systemproperties and the data in it is in this format:
[
{"name": "system.totalphysicalmemory", "value": "4.00GB"},
{"name": "system.enablenetflow", "value": "false"}
]
This is the way how I get the value for totalphysicalmemory:
SELECT
jsonb_array_element(system_properties::jsonb, 0) ->> 'value' as total_physical_memory
FROM mytable
This one works but not all of the records have the same index for totalphysicalmemory. I am trying to find a way to get the value by name instead.
I tried to crashcourse on json/postgresql but I am not getting any good results. Thank you!
This is the way how I get the value for totalphysicalmemory:
SELECT
jsonb_array_element(system_properties::jsonb, 0) ->> 'value' as total_physical_memory
FROM mytable

You can use a JSON path query
select jsonb_path_query_first(systemproperties, '$[*] ?(#.name == "system.totalphysicalmemory").value)')
from mytable;

Related

Complex JSON using JSON_MODIFY without nested arrays or escape characters (WITHOUT_ARRAY_WRAPPER)

I am using JSON_MODIFY to build complex JSON. Moving from MySQL I am struggling with the JSON functions provided by SQL Server. The issue I'm having is that SQL Server seems to construct all JSON objects in an array. There is the WITHOUT_ARRAY_WRAPPER mechanism, which seems like it should do what I want, however; there are two undesirable consequences.
It only returns one result depending on how it is used
The result is a single string with escape characters
I have constructed a simple query which illustrates my needs and the issue.
QUERY 1
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'append $.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
) AS "data";
OUTPUT 1
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
"{\"id\":1,\"name\":\"123abc\"},{\"id\":2,\"name\":\"234bcd\"}"
]
}
QUERY 2
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'append $.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH
)
) AS "data";
OUTPUT 2
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
]
}
QUERY 1
The data object is an array (which is expected), but the problem is what is in the array... A single string with escape characters.
QUERY 2
The data object is an array, which contains an array. In order to access the actual array of data, I would use something like for each obj in data[0].... The problem this poses is, for anyone consuming the JSON object, I would have to tell them:
"In this particular object the data element is an array of
arrays--You'll want to use the first and only the first
element to access the actual array of data."
I've naively tried many different combinations of JSON_MODIFY, JSON_QUERY, and CONCAT to no avail. How can I properly use JSON_MODIFY to get the following output, without the double array in data?
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
}
You are over-thinking this by trying to JSON_MODIFY an existing object.
Construct the definitions and data properties that you need, inside a subquery if necessary.
Then use FOR JSON a second time to get the outer object.
SELECT
definitions = JSON_QUERY('{"id": "INT", "name": "VARCHAR(23)"}'),
data =
(
SELECT id, name
FROM (VALUES
(1, '123abc'),
(2, '234bcd')
) v(id, name)
FOR JSON PATH
)
FOR JSON PATH;
SQL Fiddle
By trial and error, I found the solution.
Removed the append keyword from the path parameter in the JSON_MODIFY statement
Removed the WITHOUT_ARRAY_WRAPPER parameter from the FOR JSON statement.
Now the results are as expected and I don't need to explain to any consumers to "Just use data[0]"
The Query
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'$.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH
)
) AS "data";
Produces the following output
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
}

Postgres array json recent date

i have a json array like this:
[
{
"date": "26/11/2020 23:27",
"note": "test1"
},
{
"date": "22/11/2020 22:59",
"note": "test2"
},
{
"date": "18/11/2020 17:08",
"note": "test3"
}
]
I would like to take the element that has the most recent data.
My old query to get the first element was like that:
(notes\:\:json->0)\:\:json->>'note' as note,
(notes\:\:json->0)\:\:json->>'date' as date_note
step-by-step demo:db<>fiddle
SELECT
elem.value ->> 'date' as thedate,
elem.value ->> 'note' as note
FROM t,
json_array_elements(data) elem -- 1
WHERE id = 4123
ORDER BY to_timestamp(elem ->> 'date', 'DD/MM/YYYY HH24:MI') DESC -- 2
LIMIT 1 -- 3
Extract all array elements into one row
Read datetime string from date field, convert into timestamp and use it to order all array elements with most recent timestamp first
Just return the very first (= most recent) array element.

List arbitrary number of elements from a json field (postgres)

I have a json field in postgres db that contains data like
[{
"value": "+1 968 730 5680",
"label": "mobile",
"primary": true
},{
"value": "+1 909 169 4444",
"label": "mobile",
"primary": false
}]
I want to query this field to produce
+1 968 730 5680; +1 909 169 4444
Given that the number of elemets can vary.
I had enough brains to get the first element with
json_field -> 0 ->> 'value'
but am totally stuck at producing a string with all elements.
Please help.
UPDATE
Following advice below, I get an error with statement
select d ->> 'value' as val
from analyst.person
cross join jsonb_array_elements(phone) as x(d)
ERROR: column "phone" does not exist
LINE 3: cross join jsonb_array_elements(phone) as x(d)
another variant I tried
select d ->> 'value' as val
from analyst.person as person
cross join jsonb_array_elements(person.phone) as x(d)
gives error
ERROR: invalid reference to FROM-clause entry for table "person"
LINE 3: cross join jsonb_array_elements(person.phone) as x(d)
^
HINT: There is an entry for table "person", but it cannot be referenced from this part of the query.
You need to unnest your json array, extract the value and aggregate it back into a string:
select string_agg(val, '; ')
from (
select d ->> 'value' as val
from the_table
cross join lateral jsonb_array_elements(the_json_colum) as x(d)
) t
Online example: https://rextester.com/VFSRY99127

How select mysql with condition on nested array json?

i'm create a table have one json column and data of inserted has below structure:
{
"options" : {
"info" : [
{"data" : "data1", "verified" : 0},
{"data" : "data2", "verified" : 1},
... and more
],
"otherkeys" : "some data..."
}
}
i want to run a query to get data of verified = 1 "info"
this is for mysql 5.7 comunity running on windows 10
select id, (meta->"$.options.info[*].data") AS `data`
from tbl
WHERE meta->"$.options.info[*].verified" = 1
is expect the output of "data2" but the actual output is nothing.
below query worked perfectly
select id, (meta->"$.options.info[*].data") AS `data`
from tbl
WHERE meta->"$.options.info[1].verified" = 1
but i need to search all item in array not only index 1
how can fix it ?
(sorry for bad english)
Try:
SELECT `id`, (`meta` -> '$.options.info[*].data') `data`
FROM `tbl`
WHERE JSON_CONTAINS(`meta` -> '$.options.info[*].verified', '1');
See dbfiddle.

converting xml to json using postgresql

I am working on converting XML to j son string using the PostgreSQL.
we have attributecentric XML and would like to know how to convert it to j son.
Example XML:
<ROOT><INPUT id="1" name="xyz"/></ROOT>
Need to get the j son as follows:
{ "ROOT": { "INPUT": { "id": "1", "name": "xyz" }}}
got the above json format from an online tool.
any help or guidance will be appreciated.
Regards
Abdul Azeem
Basically, breakdown of this problem is the following:
extract values from given XML using xpath() function
generate and combine JSON entries using json_object_agg() function
The only tricky thing here is to combine key,value pairs together from xpath()/json_object_agg() results, which are{ "id": "1"} and { "name" : "xyz"}.
WITH test_xml(data) AS ( VALUES
('<ROOT><INPUT id="1" name="xyz"/></ROOT>'::XML)
), attribute_id(value) AS (
-- get '1' value from id
SELECT (xpath('//INPUT/#id',test_xml.data))[1] AS value
FROM test_xml
), attribute_name(value) AS (
-- get 'xyz' value from name
SELECT (xpath('//INPUT/#name',test_xml.data))[1] AS value
FROM test_xml
), json_1 AS (
-- generate JSON 1 {"id": "1"}
SELECT json_object_agg('id',attribute_id.value) AS payload
FROM attribute_id
), json_2 AS (
-- generate JSON 2 {"name" : "xyz"}
SELECT json_object_agg('name',attribute_name.value) AS payload FROM attribute_name
), merged AS (
-- Generate INPUT result - Step 1 - combine JSON 1 and 2 as single key,value source
SELECT key,value
FROM json_1,json_each(json_1.payload)
UNION ALL
SELECT key,value
FROM json_2,json_each(json_2.payload)
), input_json_value AS (
-- Generate INPUT result - Step 2 - use json_object_agg to create JSON { "id" : "1", "name" : "xyz" }
SELECT json_object_agg(merged.key,merged.value) AS data
FROM merged
), input_json AS (
-- Generate INPUT JSON as expected { "INPUT" : { "id" : "1", "name" : "xyz" } }
SELECT json_object_agg('INPUT',input_json_value.data) AS data
FROM input_json_value
)
-- Generate final reult
SELECT json_object_agg('ROOT',input_json.data)
FROM input_json;