Postgres Json List of Map - json

I have one sample json as below
{
"jsonObject":
[
{ "Name" : "XPerson",
"Age" : 18},
{ "Name" : "YPerson",
"Age" : 18}
]
}
I can have this list to N numbers. I want to separate this in different column based on Age like less than 18 in column1, between 18 to 25 in column2 and all other in column3.
How can we achieve in postgres?

It sounds like you are trying to do front end's job at database level.
with data(Age,Name) as
(select *
from jsonb_to_recordset(' {
"jsonObject": [
{
"Name": "XPerson",
"Age": 18
},
{
"Name": "YPerson",
"Age": 18
}
]
}'::jsonb -> 'jsonObject') as t("Age" int, "Name" text))
select
string_agg(case when age < 18 then name end,',') as Column1,
string_agg(case when age >= 18 and age <=25 then name end,',') as Column2,
string_agg(case when age > 25 then name end,',') as Column3
from data;

Related

Using SQLite Json Functions I want to retrieve a value base on the value near it

Lets say I have this Json and I would like to retrieve all the age values where the name equals Chris in the Array key.
{
"Array": [
{
"age": "65",
"name": "Chris"
},
{
"age": "20",
"name": "Mark"
},
{
"age": "23",
"name": "Chris"
}
]
}
That Json is present in the Json column inside my database.
by that I would like to retrieve one age column the has the age 65 and 23 because they both named Chris.
Use json_each() table-valued function to extract all the names and ages from the json array of each row of the table and json_extract() function to filter the rows for 'Chris' and get his age:
SELECT json_extract(j.value, '$.name') name,
json_extract(j.value, '$.age') age
FROM tablename t JOIN json_each(t.col, "$.Array") j
WHERE json_extract(j.value, '$.name') = 'Chris';
Change col to the name of the json column.
See the demo.

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 to get array index from Oracle JSON column?

Having a JSON like this (I know that JSON doesn't support comments. Used in this case to illustrate the idea):
{
"people": [
{ --// <-- index 0
"id": 100,
"name": "John Doe"
},
{ --// <-- index 1
"id": 101,
"name": "Jane Roe"
}
]
}
We can select values from specific elements in the array doing something like this:
SELECT name
FROM JSON_TABLE(
'{
"people": [
{
"id": 100,
"name": "John Doe"
},
{
"id": 101,
"name": "Jane Roe"
},
]
}', '$.people[*]'
COLUMNS(
ID NUMBER PATH '$.id',
NAME VARCHAR2 PATH '$.name'
)
) info
WHERE info.id = 101
Result:
NAME
--------
Jane Roe
Is there a way to get the element index in the array? Something like:
SELECT array_index --// <-- how get the array index of the element found?
FROM JSON_TABLE(
--// ...
) info
WHERE info.id = 101
Result:
ARRAY_INDEX
-----------
1
Is possible to do something like this using JSON support in Oracle 12c?
COLUMNS(
idx FOR ORDINALITY,
ID NUMBER PATH '$.id',
NAME VARCHAR2 PATH '$.name'
)
should work for you
As ArtBajji wrote, the rows itself dont have a index. Therefor you need to create a "fake id" that is relatively fixed.
This can be achieved by giving your data a order(order by id) and a index (rownum). Then select from this "modified" table
SELECT name, indx FROM (
SELECT ind.*, rownum "INDX"
FROM JSON_TABLE(
'{
"people": [
{
"id": 100,
"name": "John Doe"
},
{
"id": 101,
"name": "Jane Roe"
},
]
}', '$.people[*]'
COLUMNS(
ID NUMBER PATH '$.id',
NAME VARCHAR2 PATH '$.name'
)
) ind order by id) tab
WHERE tab.id = 101
Yields 1 for id 100 and 2 for id 101.
Be aware that the index of the elements 100 and 101 grow by one if you insert a item with a id < 100.

Parsing JSON in Postgres

I have the following JSON that I'd like to parse inside a postgresql function.
{
"people": [
{
"person_name": "Person#1",
"jobs": [
{
"job_title": "Job#1"
},
{
"job_name": "Job#2"
}
]
}
]
}
I need to know how to pull out the person_name, and then loop thru the jobs and pull out the job_title. This is as far as I've been able to get.
select ('{"people":[{"person_name":"Person#1","jobs":[{"job_title":"Job#1"},
{"job_name":"Job#2"}]}]}')::json -> 'people';
https://www.db-fiddle.com/f/vcgya7WtVdvj8q5ck5TqgX/0
Assuming that job_name in your post should be job_title. I expanded your test data to:
{
"people": [{
"person_name": "Person#1",
"jobs": [{
"job_title": "Job#11"
},
{
"job_title": "Job#12"
}]
},
{
"person_name": "Person#2",
"jobs": [{
"job_title": "Job#21"
},
{
"job_title": "Job#22"
},
{
"job_title": "Job#23"
}]
}]
}
Query:
SELECT
person -> 'person_name' as person_name, -- B
json_array_elements(person -> 'jobs') -> 'job_title' as job_title -- C
FROM (
SELECT
json_array_elements(json_data -> 'people') as person -- A
FROM (
SELECT (
'{"people":[ '
|| '{"person_name":"Person#1","jobs":[{"job_title":"Job#11"}, {"job_title":"Job#12"}]}, '
|| '{"person_name":"Person#2","jobs":[{"job_title":"Job#21"}, {"job_title":"Job#22"}, {"job_title":"Job#23"}]} '
|| ']}'
)::json as json_data
)s
)s
A Getting person array; json_array_elements expands all array elements into one row per element
B Getting person_name from array elements
C Expanding the job array elements into one row per element and getting the job_title
Result:
person_name job_title
----------- ---------
"Person#1" "Job#11"
"Person#1" "Job#12"
"Person#2" "Job#21"
"Person#2" "Job#22"
"Person#2" "Job#23"

how to get projections in mongodb with group operator

I have a table with columns Column1 & Column2 which looks like this
Colum1 Column2
A 1
A 2
A 3
B 2
B 4
B 6
If I perform following SQL in MYSQL
SELECT Column1, Column2, count(*) from Table group by Column1;
Result is
Column1 Column2 Count(*)
A 1 3
B 2 3
I want to execute similar query on MONGODB
I tried
QUERY1: db.table.aggregate({$group: {_id:"$Column1", count:{$sum:1}} })
QUERY2: db.table.aggregate({$project: {column1:1, column2:1}}, {$group: {_id:"$Column1", count:{$sum:1}} })
However the result for Query2 is same as Query1, It seems like you can not populate fields other than mentioned in $group column.
Is there a way to populate other fields in mongodb along with $group operator ?
I'm not sure I read the mysql query correctly, and I don't understand why this is particularly useful, but $first seems to accomplish the same thing.
However, as mentioned in the $first documentation, the outcome depends on the sorting so you should include a sorting criterion.
Data (column names shortened for brevity)
> db.foo.insert({"C1" : "A", "C2" : 1});
> db.foo.insert({"C1" : "A", "C2" : 2});
> db.foo.insert({"C1" : "A", "C2" : 3});
> db.foo.insert({"C1" : "B", "C2" : 2});
> db.foo.insert({"C1" : "B", "C2" : 4});
> db.foo.insert({"C1" : "B", "C2" : 6});
Aggregation Query
> db.foo.aggregate({$group: {_id:"$C1", C2: { $first: "$C2" }, count:{$sum:1}} })
Results
{
"result" : [
{
"_id" : "B",
"C2" : 2,
"count" : 3
},
{
"_id" : "A",
"C2" : 1,
"count" : 3
}
],
"ok" : 1
}