JSONB Array Output - Postgres 11.5 - json

I have a JSONB string in this format
{
"RouteId": "90679754-89f5-48d7-99e1-5192bf0becf9",
"Started": "2019-11-20T21:24:33.7294486Z",
"RouteName": "ProcessRequestsAndPublishResponse",
"MachineName": "5CG8134NJW-LA",
"ChildProfiles": [
{
"ApiMethod": "ProcessApiRequest",
"ExecuteType": null,
"DurationMilliseconds": 2521.4,
},
{
"ApiMethod": "PublishShipViaToQueue",
"ExecuteType": null,
"DurationMilliseconds": 0.6,
}
],
"DataBaseTimings": null,
"DurationMilliseconds": 2522.6
}
How do I get the output in this format
| RouteName | Metrics | Time | TotalDuration |
---------------------------------------------------------------------------------------------
| ProcessRequestsAndPublishResponse | ProcessApiRequest | 2521.4 | 2522.6 |
| ProcessRequestsAndPublishResponse | PublishShipViaToQueue | 0.6 | 2522.6 |
---------------------------------------------------------------------------------------------
Any help on this is appreciated
How do you also extend this in case there are different arrays. Sorry fairly new to the JSONB world.
{
"RouteId": "af2e9cba-11ae-43a9-813c-d24ea574ee62",
"RouteName": "GenerateRequestAndPublishToQueue",
"ChildProfiles": [
{
"ApiMethod": "PublishShipViaRequestToQueue",
"DurationMilliseconds": 0.1,
}
],
"DataBaseTimings": [
{
"ExecuteType": "OpenAsync",
"DurationMilliseconds": 0.1
},
{
"ExecuteType": "Reader",
"DurationMilliseconds": 72.1
},
{
"ExecuteType": "Close",
"DurationMilliseconds": 15.9
}
],
"DurationMilliseconds": 88.6
}
The required output is something like this
| RouteName | Metrics | Time | TotalDuration |
--------------------------------------------------------------------------------------------------------
| GenerateRequestAndPublishToQueue | PublishShipViaRequestToQueue | 0.1 | 88.6 |
| GenerateRequestAndPublishToQueue | OpenAsync | 0.1 | 88.6 |
| GenerateRequestAndPublishToQueue | Reader | 72.1 | 88.6 |
| GenerateRequestAndPublishToQueue | Close | 15.9 | 88.6 |
---------------------------------------------------------------------------------------------------------

You can do a lateral join and use jsonb_to_recordset() to expand the inner json array as an inline table:
select
js ->> 'RouteName' RouteName,
xs."ApiMethod" Metrics,
xs."DurationMilliseconds" "Time",
js ->> 'DurationMilliseconds' TotalDuration
from t
cross join lateral jsonb_to_recordset( js -> 'ChildProfiles')
as xs("ApiMethod" text, "DurationMilliseconds" numeric)
Demo on DB Fiddlde:
routename | metrics | Time | totalduration
:-------------------------------- | :-------------------- | -----: | :------------
ProcessRequestsAndPublishResponse | ProcessApiRequest | 2521.4 | 2522.6
ProcessRequestsAndPublishResponse | PublishShipViaToQueue | 0.6 | 2522.6

Related

QueryDSL with DB2 fetching Nested Json object or Json array aggregation Response

I am trying to fetch nested JSON objects and JSON List from Database using QueryDSL. I have used a native query with LISTAGG and JSON_OBJECT.
Native Query :
SELECT b.id,b.bankName,b.account,b.branch,(select CONCAT(CONCAT('[',LISTAGG(JSON_OBJECT('accountId' value c.accountId, 'name' value customer_name,'amount' value c.amount),',')),']') from CUSTOMER_DETAILS c where c.bankId = b.id) as customers from BANK_DETAILS b
BANK_DETAILS
+----+---------+---------+----------+
| id | BankName| account | branch |
+----+---------+---------+----------+
| 1 | bank1 | savings | branch1 |
| 2 | bank2 | current | branch2 |
+----+---------+---------+----------+
CUSTOMER_DETAILS
+----+-----------+---------------+----------+-----------+
| id | accountId | customer_name | amount | BankId |
+----+-----------+---------------+----------+-----------+
| 1 | 50123 | Abc1 | 150000 | 1 |
| 2 | 50124 | Abc2 | 25000 | 1 |
| 3 | 50125 | Abc3 | 50000 | 2 |
| 4 | 50126 | Abc4 | 250000 | 2 |
+----+-----------+---------------+----------+-----------+
Expected Output for the above tables
[{
"id": "1",
"bankName": "bank1",
"account": "savings",
"branch": "branch1",
"customers": [
{
"accountId": "50123",
"Name": "Abc1",
"amount": 150000
},
{
"accountId": "50124",
"Name": "Abc2",
"amount": 25000
},
]
},{
"id": "2",
"bankName": "bank3",
"account": "current",
"branch": "branch2",
"customers": [
{
"accountId": "50125",
"name": "Abc3",
"amount": 50000
},
{
"accountId": "50126",
"Name": "Abc4",
"amount": 250000
},
]
}]
i have tried with writing this native query in QueryDSL with the below multiple queries for make the same expected output with the forEach loop.
class Repository {
private SQLQueryFactory queryFactory;
public Repository (SQLQueryFactory queryFactory){
this.queryFactory = queryFactory;
}
public void fetchBankDetails(){
List<BankDetails> bankList = queryFactory.select(QBankDetails.bankDetails)
.from(QBankDetails.bankDetails);
bankList.forEach(bankData ->{
List<CustomerDetails> customerList = queryFactory.select(QCustomerDetails.customerDetails)
.from(QCustomerDetails.customerDetails)
.where(QCustomerDetails.customerDetails.bankId.eq(bankData.bankId));
bankData.setCustomerList(customerList)
});
System.out.println(bankList);
}
}
I need to improve my code and convert it into a single query using QueryDSL to return the expected output
Is there any other way or any suggestions?

Find matches in JSON array field in MySQL

Given a JSON object type column in table t, e.g.
| id | obj |
| -- | ---------------------------------- |
| 1 | { "params": { "id": [13, 23]} } |
| 2 | { "params": { "id": [13, 24]} } |
| 3 | { "params": { "id": [11, 23, 45]} }|
and a list of numeric values, e.g. [12, 23, 45].
We need to check every record if it contains values from the given list.
So, the desired result would be
| id | matches |
| -- | -------- |
| 1 | [23] |
| 3 | [23, 45] |
Could someone please help with such a query for the MySQL 8?
Thank you!
You can use json_table:
select t2.id, t2.n_obj from (
select t1.id, (select json_arrayagg(ids.v)
from json_table(t1.obj, "$.params.id[*]" columns(v text path '$')) ids
where json_contains('[12, 23, 45]', ids.v, '$'))
n_obj from t t1) t2
where t2.n_obj is not null;

MySQL JSON_OBJECT AGG vs non-AGG, and how it precisely works

I've been busy with a query that solidifies multiple results in a single group. The table has the following setup
+----------+----------+----------+----------+------------+
| dotw | start | end | delivery | restaurant |
+----------+----------+----------+----------+------------+
| FRIDAY | 17:00:00 | 23:00:00 | 1 | 665 |
| FRIDAY | 17:00:00 | 23:00:00 | 0 | 665 |
| MONDAY | 17:00:00 | 23:00:00 | 1 | 665 |
| MONDAY | 17:00:00 | 23:00:00 | 0 | 665 |
| SATURDAY | 17:00:00 | 23:00:00 | 1 | 665 |
| SATURDAY | 17:00:00 | 23:00:00 | 0 | 665 |
| SUNDAY | 11:00:00 | 23:00:00 | 1 | 665 |
| SUNDAY | 11:00:00 | 23:00:00 | 0 | 665 |
| THURSDAY | 17:00:00 | 23:00:00 | 1 | 665 |
| THURSDAY | 17:00:00 | 23:00:00 | 0 | 665 |
+----------+----------+----------+----------+------------+
This is what I want to achieve, with the expanded JSON format:
+------------+------------------------------------------------------------+
| restaurant | json |
+------------+------------------------------------------------------------+
| 665 | {} |
+------------+------------------------------------------------------------+
{
"1":{
"MONDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"TUESDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"WEDNESDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"THURSDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"FRIDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"SATURDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"SUNDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
}
},
"0":{
"MONDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"TUESDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"WEDNESDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"THURSDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"FRIDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"SATURDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
},
"SUNDAY":{
"CLOSINGTIME":"value",
"OPENINGTIME":"value"
}
}
}
I've written the following query, but it only works after getting the first value of each dictionary.
SELECT
oh.restaurant,
JSON_OBJECTAGG(
oh.delivery,
JSON_OBJECT(
oh.dotw,
JSON_OBJECT(
'openingtime', oh.start,
'closingtime', oh.end)))
FROM opening_hours oh
WHERE restaurant = 665
GROUP BY oh.restaurant
If I try to JSON_OBJECTAGG() or JSON_ARRAYAGG() the nested JSON it returns an invalid grouping error.
Do I need to join the query on itself to work? And why does MySQL not understand what I want?
As expected MySQL handles grouping in a rather special way. I fixed the problem by joining the query on itself.
SELECT
oh.restaurant,
JSON_OBJECTAGG(
oh.delivery,
oh.JSONoh) OpeningHours
FROM (
SELECT
oh.restaurant,
oh.delivery,
JSON_OBJECTAGG(
oh.dotw,
JSON_OBJECT(
'Openingtime', oh.start,
'Closingtime', oh.end)) JSONoh
FROM opening_hours oh
GROUP BY oh.restaurant, oh.delivery) oh
GROUP BY oh.restaurant
I am stuck working in MYSQL 5, so I am not familiar with the JSON_AGG functions, but you can achieve what you want using GROUP_CONCAT as follows (beware, it's clunky, and untested):
SELECT r,CONCAT("{'",dt,"':'",GROUP_CONCAT(line2),"}")) as json
FROM (
SELECT r,dt,CONCAT("{'",dw,"':'",GROUP_CONCAT(line1),"}") AS line2
FROM (
SELECT restaurant r,delivery dt,dotw dw,CONCAT("{'start':'",start,"', 'end':'",end,"}") line1
FROM opening_hours
WHERE restaurant = 665 # <<< remove this clause to include all restaurants
) AS SQ1
GROUP BY r,dt,dw
ORDER BY r,dt,dw
) as SQ2
GROUP BY r,dt
ORDER BY r,dt;
This answer assumes you feed the '655' into the WHERE clause of the inner subquery to get a report for a single restaurant. If you need a report for multiple restaurants, just remove the WHERE clause.

Filter google spreadsheet by date and time

I have the following data in Google Spreadsheet:
| Users | Timestamp |
| 1 | 2019-09-19T09:28:00.598Z |
| 2 | 2019-09-20T09:28:00.598Z |
| 3 | 2019-09-21T09:28:00.598Z |
| 4 | 2019-09-22T09:28:00.598Z |
| 5 | 2019-09-23T09:28:00.598Z |
How can I make a Charts filter for it? Apparently Charts.newNumberRangeFilter does not work with dates.
Use DateRangeFilter instead
Sample:
var myDateRangeFilter = new google.visualization.ControlWrapper({
'controlType': 'DateRangeFilter',
'containerId': 'chartFilter',
'options': {
'filterColumnLabel': 'Date',
'ui': {
format: {
pattern: 'yyyy/MM/dd HH:mm:ss'
},
step: 'day'
}
}
})

hive json data parsing

My JSON Data is something like this in the table json_table and column: json_col
{
"href": "example.com",
"Hosts": {
"cluster_name": "test",
"host_name": "test.iabc.com"
},
"metrics": {
"cpu": {
"cpu_user": [
[
0.7,
1499795941
],
[
0.3,
1499795951
]
]
}
}
}
I want to get this into a table json_data in the below format
+-------------+-------+------------+
| metric_type | value | timestamp |
+-------------+-------+------------+
| cpu_user | 0.7 | 1499795941 |
+-------------+-------+------------+
| cpu_user | 0.3 | 1499795951 |
+-------------+-------+------------+
I tried getting the values using get_json_object
select get_json_object(json_col,'$.metrics.cpu.cpu_user[1]') from json_table
,this gives me
[0.3,1499795951]
How do I use the explode function from here to get the desired output?
select 'cpu_user' as metric_type
,val_ts[0] as val
,val_ts[1] as ts
from (select split(m.col,',') as val_ts
from json_table j
lateral view explode(split(regexp_replace(get_json_object(json_col,'$.metrics.cpu.cpu_user[*]'),'^\\[\\[|\\]\\]$',''),'\\],\\[')) m
) m
;
+-------------+-----+------------+
| metric_type | val | ts |
+-------------+-----+------------+
| cpu_user | 0.7 | 1499795941 |
| cpu_user | 0.3 | 1499795951 |
+-------------+-----+------------+
You can also implement SerDe and InputFormat interface based on JSON data, instead of using UDF.
here are some referance:
http://blog.cloudera.com/blog/2012/12/how-to-use-a-serde-in-apache-hive/
https://github.com/xjtuzxh/inceptor-inputformat