How to ORDER BY a JSON value? - mysql

I have this column named "data" and has some JSON in it.
What i want to do is order my SQL query by the "toptimes" value.
My actual and desired query:
"SELECT core_members.pp_thumb_photo,name,member_group_id,data FROM game_accounts.accounts INNER JOIN website_accounts.core_members ON member_id = account_id WHERE member_group_id IN (4, 7, 8, 6) ORDER BY data ->> '$[0].toptimes' ASC LIMIT 100"
My JSON code:
[ { "daily_login": { "yearday": 56, "hour": 11, "second": 33, "minute": 18, "weekday": 3, "month": 1, "monthday": 26, "timestamp": 1582715913, "year": 120, "isdst": 0 }, "toptimes": 49, "daily_login_streak": 1, "hunters": 59, "playtime": 226099647, "awards": [ ], "nickname": "RandomNick" } ]

It has to be something on these lines:
ORDER BY JSON_VALUE(data,'$.daily_login.toptimes)
Access toptimes through daily_login within the JSON object.

Presumably, you want:
order by data ->> '$[0].toptimes'
This will order the resultset according to the value of toptimes in the first element of your JSON array.
If you are storing a JSON object and not an array (although this is not what you showed in yuour sample data), then:
order by data ->> '$.toptimes'

I had a problem, only for MS SQL. It helped to convert a string to a number.
SELECT TOP (1000) [Uuid],
JSON_VALUE(json, '$.likesCount') as likesCount,
FROM [dbo].[Playlists]
order by CONVERT(bigint, JSON_VALUE(json, '$.likesCount')) desc

Related

Creating nested array in JSON

I have a table structure like this:
I want to create a JSON out of this table in this form:
{
"EntityId": 100000,
"Years": [
{
"Year": 2008,
"Monthly": [
{
"Month": 1,
"Count1": 49,
"Count2": 2
},
{
"Month": 2,
"Count1": 45,
"Count2": 1
},
.
.
.
]
},
{
"Year": 2009,
"Monthly": [
{
"Month": 1,
"Count1": 36,
"Count2": 1
},
{
"Month": 2,
"Count1": 33,
"Count2": 0
},
.
.
.
]
},
.
.
.
.
]
}
This table will always be queried for a single EntityId.
I am not able to nest my arrays also the years are repeating (the number of times the year gets repeated is the number of months inside that year, so if I have 12 months of data for the year 2008 then this year's data gets repeated 12 times) when I try the below query:
select f.EntityId,
(
select TOP 1 [year] as [year],
(
select [month] as [month],
[count1] as [count1],
[count2] as [count2],
from someTable m
where m.EntityId = f.EntityId and m.Year = y.Year
for json path
) as [months]
from someTable y
where y.EntityId = f.EntityId and y.Year = f.Year
for json path
) AS years
from someTable f
where f.EntityId = f.EntityId
for json path
Try this.
SELECT
OuterData1,
OuterData2,
,(SELECT InnerData1, InnerData2
FROM Table2
FOR JSON PATH) InnerJson
OuterData3,
OuterData4
FROM Table1
FOR JSON PATH

Find object by key/value in an array in postgresql jsonb column

I have the following table:
CREATE TABLE api_data (
id bigserial NOT NULL PRIMARY KEY,
content JSONB NOT NULL
);
Now I insert an array like this into the content column:
[{ "id": 44, "name": "address One", "petId": 1234 },
{ "id": 45, "name": "address One", "petId": 1234 },
{ "id": 46, "name": "address One", "petId": 1111 }]
What I want next is to get exactly the objects that have the "petId" set to a given value.
I figured I could do
select val
from api_data
WHERE content #> '[{"petId":1234}]'
But that returns the whole array.
Another thing I found is this query:
select val
from api_data
JOIN LATERAL jsonb_array_elements(content) obj(val) ON obj.val->>'petId' = '1234'
WHERE content #> '[{"petId":1234}]'
Which returns the object I am looking for, but three times which matches the number of elements in the array.
What I actually need is a result like this:
[{ "id": 44, "name": "address One", "petId": 1234 },
{ "id": 45, "name": "address One", "petId": 1234 }]
If you are using Postgres 12, you can use a JSON path expression:
select jsonb_path_query_array(content, '$[*] ? (#.petId == 1234)') as content
from api_data
where content #> '[{"petId":1234}]';
If you are using an older version, you need to unnest and aggregate manually:
select (select jsonb_agg(e)
from jsonb_array_elements(d.content) as t(e)
where t.e #> '{"petId":1234}') as content
from api_data d
where d.content #> '[{"petId":1234}]'

Query jsonb column to match an array of keys

I have a table items which has a jsonb column data.
The data column is something like this {"name": "aaa", "age": 23, "job": "dev"}.
How do I select items that the data has only the keys name, age?.
You can use the ? and the ?& operators.
For your usecase, it will be:
SELECT * FROM table WHERE (NOT data ? 'job') AND (data ?& array ['name', 'age'])
Use the delete operator -, example:
with items (data) as (
values
('{"name": "aaa", "age": 23}'::jsonb),
('{"name": "aaa", "age": 23, "job": "dev"}'),
('{"name": "aaa", "age": 23, "gender": "f"}')
)
select *
from items
where data - 'name'- 'age' = '{}'
data
----------------------------
{"age": 23, "name": "aaa"}
(1 row)
In Postgres 10+ you can use a text array:
select *
from items
where data - array['name', 'age'] = '{}'

Sum of json array

I have json type field, something like this
data
{"age": 44, "name": "Jun"}
{"age": 19, "name": "Pablo", "attempts": [11, 33, 20]}
{"age": 33, "name": "Maria", "attempts": [77, 10]}
Here some json data have "attempts" array, some not. When json have this array, I need get sum of array elements in different field, need result like
data , sum_of_array
{"age": 44, "name": "Jun"} , (nothing here)
{"age": 19, "name": "Pablo", "attempts": [11, 33, 20]} , 64
{"age": 33, "name": "Maria", "attempts": [77, 10]} , 87
SELECT attempts.id,
sum(vals.v::integer) sum_attempts
FROM attempts
LEFT JOIN LATERAL jsonb_array_elements_text(val->'attempts') vals(v)
ON TRUE
GROUP BY attempts.id;
Use json_array_elements_text if you are using json instead of jsonb.
This works if you have unique id identity column in your table
SELECT your_table.*, tt.sum FROM your_table
LEFT JOIN (
select id, SUM(arrvals) as sum FROM (
select id, json_array_elements_text(CAST(your_json_column->>'attempts' AS json))::NUMERIC as arrvals from your_table
)t
group by id
) tt
ON your_table.id = tt.id

Get aggregate sum of json array in Postgres NOSQL json data

How to get aggregate SUM(amount) from "refunds" array in postgres json select
Following is my data schema and structure:
Table Name: transactions
Column name: data
{
"id": "tran_6ac25129951962e99f28fa488993",
"amount": 1200,
"origin_amount": 3900,
"status": "partial_refunded",
"description": "Subscription#sub_a67d59efb2bcbf73485a ",
"livemode": false,
"refunds": [
{
"id": "refund_ee4192ffb6d2caa490a1",
"amount": 1200,
"status": "refunded",
"created_at": 1426412340,
"updated_at": 1426412340,
},
{
"id": "refund_0e4a34e4ee7281d369df",
"amount": 1500,
"status": "refunded",
"created_at": 1426412353,
"updated_at": 1426412353,
}
]
}
Out put should be: 1200+1500 = 2700
Output
|---------
|total
|---------
|2700
Please provide global solution and not with static data
This should work on 9.3+
WITH x AS( SELECT
'{
"id": "tran_6ac25129951962e99f28fa488993",
"amount": 1200,
"origin_amount": 3900,
"status": "partial_refunded",
"description": "Subscription#sub_a67d59efb2bcbf73485a ",
"livemode": false,
"refunds": [
{
"id": "refund_ee4192ffb6d2caa490a1",
"amount": 1200,
"status": "refunded",
"created_at": 1426412340,
"updated_at": 1426412340
},
{
"id": "refund_0e4a34e4ee7281d369df",
"amount": 1500,
"status": "refunded",
"created_at": 1426412353,
"updated_at": 1426412353
}
]
}'::json as y),
refunds AS(
SELECT json_array_elements(y->'refunds') as j FROM x)
SELECT sum((j->>'amount')::int) FROM refunds;
WITH AllRefunds AS ( SELECT jsonb_array_elements(data->'refunds') AS refund FROM transactions)
SELECT SUM( CAST ( refund ->> 'amount' AS INTEGER )) FROM AllRefunds;
If you need to know how the query is built:
1.
WITH AllRefunds AS ( SELECT jsonb_array_elements(data->'refunds') FROM transactions)
SELECT * FROM AllRefunds;
This selects all elements as JSON objects (done via ->) from the array refunds that were found in transactions table and stores it in a new table AllRefunds. This new table only consists of one unnamed column.
2.
WITH AllRefunds AS ( SELECT jsonb_array_elements(data->'refunds') AS refund FROM transactions)
SELECT * FROM AllRefunds;
Here the added (second) AS renames the currently unnamed column inside AllRefunds to refund
3.
WITH AllRefunds AS ( SELECT jsonb_array_elements(data->'refunds') AS refund FROM transactions)
SELECT SUM( CAST ( refund ->> 'amount' AS INTEGER )) FROM AllRefunds;
Our array entries are JSON objects. So we return the field amount as a simple string with ->> that we then cast to Integers and SUM all entries up.