Postgres nested JSON array using row_to_json - json

I am trying to create nested json array using 2 tables.
I have 2 tables journal and journaldetail.
Schema is -
journal : journalid, totalamount
journaldetail : journaldetailid, journalidfk, account, amount
Relation between journal and journaldetail is one-to-many.
I want the output in following format :
{ journalid : 1,
totalamount : 1000,
journaldetails : [
{
journaldetailid : j1,
account : "abc",
amount : 500
},
{
journaldetailid : j2,
account : "def",
amount : 500
}
]}
However, by writing this query as per this post the query is:
select j.*, row_to_json(jd) as journal from journal j
inner join (
select * from journaldetail
) jd on jd.sjournalidfk = j.sjournalid
and the output is like this :
{ journalid : 1,
totalamount : 1000,
journaldetails :
{
journaldetailid : j1,
account : "abc",
amount : 500
}
}
{ journalid : 1,
totalamount : 1000,
journaldetails :
{
journaldetailid : j2,
account : "def",
amount : 500
}
}
I want the child table data as nested array in the parent.

I found the answer from here:
Here is the query :
select row_to_json(t)
from (
select sjournalid,
(
select array_to_json(array_agg(row_to_json(jd)))
from (
select sjournaldetailid, saccountidfk
from btjournaldetail
where j.sjournalid = sjournalidfk
) jd
) as journaldetail
from btjournal j
) as t
This gives output in array format.

Related

Delete value from nested json - postgres

I have the json block modeled below. I want to selectively delete individual blocks from my_items based on the id which is AAA and BBB in my sample. ie if I tried to delete the AAA block under my_items I would want tojust delete the {"id" : "AAA"} but if wanted to delete the BBB block it would delete the larger {"name" : "TestRZ", "id" : "BBB", "description" : ""} block.
I know I can use the #- to remove whole blocks like SELECT '{sample_json}'::jsonb #- '{my_items}' would purge out the whole my_items block. But I dont know how to use this to conditionally delete children under a parent block of json. I have also used code similar to this example to append data inside a nested structure by reading in the node of the nested structure cat-ing new data to it and rewriting it. UPDATE data SET value= jsonb_set(value, '{my_items}', value->'items' || (:'json_to_adds'), true) where id='testnofeed'.
But I dont know how to apply either of these methods to: 1)Delete data in nested structure using #- or 2)Do the same using `jsonb_set. Anyone have any guidance for how to do this using either of these(or another method).
{
"urlName" : "testurl",
"countryside" : "",
"description" : "",
"my_items" : [
{
"id" : "AAA"
},
{
"name" : "TestRZ",
"id" : "BBB",
"description" : ""
},
],
"name" : "TheName"
}
Data is stored in value jsonb. when I update I will be able to pass in a unique kind so that it only updates this json in one row in db.
-- Table Definition
CREATE TABLE "public"."data" (
"id" varchar(100) NOT NULL,
"kind" varchar(100) NOT NULL,
"revision" int4 NOT NULL,
"value" jsonb
);
This works in PostgreSQL 12 and later with jsonpath support. If you do not have jsonpath, then please leave a comment.
with data as (
select '{
"urlName" : "testurl",
"countryside" : "",
"description" : "",
"my_items" : [
{
"id" : "AAA"
},
{
"name" : "TestRZ",
"id" : "BBB",
"description" : ""
}
],
"name" : "TheName"
}'::jsonb as stuff
)
select jsonb_set(stuff, '{my_items}',
jsonb_path_query_array(stuff->'my_items', '$ ? (#."id" <> "AAA")'))
from data;
jsonb_set
---------------------------------------------------------------------------------------------------------------------------------------------------
{"name": "TheName", "urlName": "testurl", "my_items": [{"id": "BBB", "name": "TestRZ", "description": ""}], "countryside": "", "description": ""}
(1 row)
To update the table directly, the statement would be:
update data
set value = jsonb_set(value, '{my_items}',
jsonb_path_query_array(value->'my_items',
'$ ? (#."id" <> "AAA")'));
This works for versions before PostgreSQL 12:
with data as (
select 1 as id, '{
"urlName" : "testurl",
"countryside" : "",
"description" : "",
"my_items" : [
{
"id" : "AAA"
},
{
"name" : "TestRZ",
"id" : "BBB",
"description" : ""
}
],
"name" : "TheName"
}'::jsonb as stuff
), expand as (
select d.id, d.stuff, e.item, e.rn
from data d
cross join lateral jsonb_array_elements(stuff->'my_items') with ordinality as e(item, rn)
)
select id, jsonb_set(stuff, '{my_items}', jsonb_agg(item order by rn)) as new_stuff
from expand
where item->>'id' != 'AAA'
group by id, stuff;
id | new_stuff
----+---------------------------------------------------------------------------------------------------------------------------------------------------
1 | {"name": "TheName", "urlName": "testurl", "my_items": [{"id": "BBB", "name": "TestRZ", "description": ""}], "countryside": "", "description": ""}
(1 row)
The direct update for this is a little more involved:
with expand as (
select d.id, d.value, e.item, e.rn
from data d
cross join lateral jsonb_array_elements(value->'my_items')
with ordinality as e(item, rn)
), agg as (
select id, jsonb_set(value, '{my_items}', jsonb_agg(item order by rn)) as new_value
from expand
where item->>'id' != 'AAA'
group by id, value
)
update data
set value = agg.new_value
from agg
where agg.id = data.id;

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.

Couchbase N1QL query sum from sub document array

I have the following document model in my couchbase db
{
type:"account"
id : "123",
transactions: [
{
type : "credit",
value : 100
},
{
type : "debit",
value : 10
}
]
}
How do i query all the account Ids and their sum of all credits ?
Using AS ARRAY functions https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/arrayfun.html
SELECT d.id,
ARRAY_SUM(ARRAY v.`value` FOR v IN d.transactions WHEN v.type = "credit" END) AS s
FROM default AS d
WHERE d.type = "account";
OR
Using subquery expression https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/subqueries.html
SELECT d.id,
(SELECT RAW SUM(d1.`value`)
FROM d.transactions AS d1
WHERE d1.type = "credit")[0] AS s
FROM default AS d
WHERE d.type = "account";

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;

Mysql to MongoDB and Query Equivalent to this schema

I have a complex location database with the following schema :
table States
id : INT PK AutoIncrement
name : VarChar 50 UNIQUE
table Counties
id: INT PK AutoIncrement
stateID : INT ForeignKey ->States(id)
name : VARCHAR(50)
table Towns :
id: INT PK AutoIncrement
stateID : INT ForeignKey ->States(id)
countyID : INT ForeignKey ->Counties(id)
name : VARCHAR(50)
table listings
id : INT PK autoincrement
name: varchar(50)
stateID: INT
countyID: INT
townID: INT
When I want to display some statistic data about geographical repartition in a tree form like this :
state1 (105 results)
county 1 (50 results)
county 2 (55 results)
Town 1 ( 20 results)_
Town 2 ( 35 results)
state2 (200 results)
ect...
In mySQL I would had done this kind of queries :
**1st level : **
select count(*) as nb, S.namem, S.id as stateID from listings L INNER JOIN States S ON S.id=L.stateID GROUP BY S.id;
**2d level : **
foreach(results as $result){
$sql = "select count(*) as nb, from listings L INNER JOIN Counties C ON C.id=L.countyID WHERE L.stateID=".$result['stateID'];
});
and so on...There is a way to do that in a unique long query in MySQL too.
This is a trivial query and it is very fast on a SSD disk in Mysql.
I am starting to learn mongoDB and I want to know what kindof schema I should use to store my location data to optimize this $count() and $group() operations.
And which mongo query would do the job?
Store the documents with a structure like the listings table:
{
"name" : "listing0",
"state" : "Maryland",
"county" : "Washington",
"town" : "Faketown"
}
Then just find the number of listings per (state, country, town) triple with the aggregation pipeline
> db.listings.aggregate([
// hopefully an initial match stage to select a subset of search results or something
{ "$group" : { "_id" : { "state" : "$state", "county" : "$county", "town" : "$town" }, "count" : { "$sum" : 1 } } }
])
From here you can compute the numbers for the higher level of the tree by iterating over the result cursor, or you can run analogous pipelines to compute the numbers at the higher level of the tree. For example, for the county numbers in a specific state
> db.listings.aggregate([
// hopefully an initial match stage to select a subset of search results or something
{ "$match" : { "state" : "Oregon" } },
{ "$group" : { "_id" : { "state" : "$state", "county" : "$county" }, "count" : { "$sum" : 1 } } }
])