Is such a result possible with a query from an SQL database? - mysql

I want to fire a query to get such a result:
[{
id: 1,
brandName: "x"
brandModels: [
{id: 1, modelName: "abc", createdAt: "yyyy-mm-dd"},
{id: 2, modelName: "def", createdAt: "yyyy-mm-dd"},
]
},
{
id: 2,
brandName: "y"
brandModels: [
{id: 4, modelName: "ghi", createdAt: "yyyy-mm-dd"},
{id: 5, modelName: "jkl", createdAt: "yyyy-mm-dd"},
]
}]
Tables Schema
BrandsTable
{id, brandName, brand_id}
ModelsTable
{id, modelName, createdAt}
I guess it's not possible like that? I don't have any experience with text-based databases, but I can well imagine that this can be achieved with a MongoDB. Because ultimately I want to have a js object at the end of the day.

Here's an example but I have not tested it:
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'id', b.id,
'brandName', b.brandName,
'brandModels', m.modelArray
)
) AS joined_result
FROM BrandTable AS b
JOIN (
SELECT brand_id, JSON_ARRAYAGG(
JSON_OBJECT(
'id', id,
'modelName', modelName,
'createdAt', createdAt
)
) AS modelArray
FROM ModelsTable
GROUP BY brand_id
) AS m USING (brand_id);
Note that I had to assume the ModelsTable also contains a column for brand_id, otherwise there is nothing to use in the join condition.
Read documentation for JSON_OBJECT() and JSON_ARRAYAGG() for more information about how these functions work.

Related

Mysql JSON output using json_object

I have been hacking at this for days now and just cannot get the final piece of the puzzle working....
The problem seems to get a nested object with 2 nested objects at the same level?
I need to get an output as follows:
{
"Id": "19115",
"ClassScheduleId": "2143",
"MaxCapacity": "30",
"WebCapacity": "20",
"TotalBooked": "0",
"TotalBookedWaitlist": "0",
"WebBooked": "0",
"SemesterId": null,
"IsCanceled": "0",
"Substitute": "0",
"Active": "1",
"IsWaitlistAvailable": "0",
"IsEnrolled": "0",
"HideCancel": "0",
"IsAvailable": "0",
"StartDateTime": "2021-09-06T09:15:00+02:00",
"EndDateTime": "2021-09-06T10:15:00+02:00",
"LastModifiedDateTime": "2021-09-07T02:35:21+02:00",
"StaffId": "100000237",
"BookingStatus": "PaymentRequired",
"VirtualStreamLink": null,
"ClassDescription": {
"Id": "257",
"Active": "0",
"Description": "<div>Designed to burn calories while toning and lengthening, this challenging class mixes intense, high-impact cardio and plyometric training with full body conditioning and yoga. Using popular and motivating music, this fast-paced, high energy class will help create that long and lean look. No class is ever the same to ensure progressive results</div>",
"LastUpdated": "2021-08-17T15:31:21+02:00",
"Name": "Bottoms Up",
"Notes": "",
"Prereq": "",
"Program": {
"Id": "26",
"Name": "Classes",
"ScheduleType": "Class",
"CancelOffset": "0"
},
"SessionType": {
"Id": "207",
"Type": "All",
"Name": "Spinning",
"NumDeducted": "1",
"ProgramId": "26"
}
}
}
My last attempt, which I think is "close" is just not working and throwing an error :-(
SELECT json_arrayagg(
json_object(
'ClassScheduleId', c.ClassScheduleId,
'MaxCapacity', c.MaxCapacity,
'WebCapacity', c.WebCapacity,
'TotalBooked', c.TotalBooked,
'TotalBookedWaitlist', c.TotalBookedWaitlist,
'WebBooked', c.WebBooked,
'IsCanceled', c.IsCanceled,
'Substitute', c.Substitute,
'Active', c.Active,
'IsWaitlistAvailable', c.IsWaitlistAvailable,
'IsEnrolled', c.IsEnrolled,
'HideCancel', c.HideCancel,
'Id', c.Id,
'IsAvailable', c.IsAvailable,
'StartDateTime', c.StartDateTime,
'EndDateTime', c.EndDateTime,
'LastModifiedDateTime', c.LastModifiedDateTime,
'BookingStatus', c.BookingStatus
'ClassDescription', json_object(
'Active', cd.Active,
'Description', cd.Description,
'Id', cd.Id,
'LastUpdated', cd.LastUpdated,
'Name', cd.Name,
'Notes', cd.Notes,
'Prereq', cd.Prereq,
GROUP_CONCAT(
'Program', json_object(
'Id', p.Id,
'Name', p.Name,
'ScheduleType', p.ScheduleType,
'CancelOffset', p.CancelOffset
),
'SessionType', json_object(
'Type', st.Type,
'Id', st.Id,
'Name', st.Name,
'NumDeducted', st.NumDeducted,
'ProgramId', st.ProgramId
)
)
)
)
)
FROM Classes as c
LEFT JOIN ClassDescription as cd ON cd.Id = c.ClassDescriptionId
LEFT JOIN Program as p ON p.Id = cd.ProgramId
LEFT JOIN SessionType as st ON st.Id = cd.SessionTypeId
Any ideas where I can get better documentation or an SQL visual editor that has the capability to format/build these types of queries?
Thanks in advance for any input!
Bingo!!! Devil is always in the detail
Seems I missed the , after 'BookingStatus', c.BookingStatus and I also removed the GROUP_CONCAT!
This works perfect!
SELECT json_arrayagg(
json_object(
'ClassScheduleId', c.ClassScheduleId,
'MaxCapacity', c.MaxCapacity,
'WebCapacity', c.WebCapacity,
'TotalBooked', c.TotalBooked,
'TotalBookedWaitlist', c.TotalBookedWaitlist,
'WebBooked', c.WebBooked,
'IsCanceled', c.IsCanceled,
'Substitute', c.Substitute,
'Active', c.Active,
'IsWaitlistAvailable', c.IsWaitlistAvailable,
'IsEnrolled', c.IsEnrolled,
'HideCancel', c.HideCancel,
'Id', c.Id,
'IsAvailable', c.IsAvailable,
'StartDateTime', c.StartDateTime,
'EndDateTime', c.EndDateTime,
'LastModifiedDateTime', c.LastModifiedDateTime,
'BookingStatus', c.BookingStatus,
'ClassDescription', json_object(
'Active', cd.Active,
'Description', cd.Description,
'Id', cd.Id,
'LastUpdated', cd.LastUpdated,
'Name', cd.Name,
'Notes', cd.Notes,
'Prereq', cd.Prereq,
'Program', json_object(
'Id', p.Id,
'Name', p.Name,
'ScheduleType', p.ScheduleType,
'CancelOffset', p.CancelOffset
),
'SessionType', json_object(
'Type', st.Type,
'Id', st.Id,
'Name', st.Name,
'NumDeducted', st.NumDeducted,
'ProgramId', st.ProgramId
)
)
)
)
FROM Classes as c
LEFT JOIN ClassDescription as cd ON cd.Id = c.ClassDescriptionId
LEFT JOIN Program as p ON p.Id = cd.ProgramId
LEFT JOIN SessionType as st ON st.Id = cd.SessionTypeId

How to get all posts in a table with comments and author data

I have three different tables:
users
posts
comments
And I would like to get a result like this:
posts: [
{
id: 1,
text: "Looking for something else specific here",
author: {
id: 3,
image: "https://lh3.googleusercontent.com",
username: "AR"
},
comments: [
{
id: 1,
text: 'Try this!',
author: {
id: 4,
image: "https://lh3.googleusercontent.com",
username: "AM"
}
},
{
id: 2,
text: 'Thanks!',
author: {
id: 3,
image: "https://lh3.googleusercontent.com",
username: "AR"
}
},
],
created_at: "2021-08-18 01:16:58.000000",
updated_at: "2021-08-18 01:16:58.000000"
},
{
id: 2,
text: "Looking for something specific here",
author: {
id: 4,
image: "https://lh3.googleusercontent.com",
username: "AM"
},
comments: [
null
],
created_at: "2021-08-18 01:18:13.000000",
updated_at: "2021-08-18 01:18:13.000000"
}
]
So far I have this:
SELECT
cast(concat('[', group_concat(
JSON_OBJECT(
'id', p.id,
'text', p.text,
'author', JSON_OBJECT(
'id', u.id,
'username', u.ofdb_username,
'image', u.image
),
'comments', JSON_OBJECT(
'id', c.id,
'text', c.text,
'created_at', c.created_at,
'updated_at', c.updated_at
),
'created_at', p.created_at,
'updated_at', p.updated_at
) SEPARATOR ','), ']') as json) as posts
FROM posts as p
LEFT JOIN users as u
ON p.users_id = u.id
LEFT JOIN comments as c
on c.posts_id = p.id
However if there is more than one comment, the same post is repeated twice because of the LEFT JOIN. I also haven't tried to join users a second time to get the comment's author data.
Since I was using Next.js, I ended up switching to Prisma's ORM model which made this so much easier.
I know this isn't a direct answer but to all futurecomers: try to forgo writing SQL code and use an ORM like Prisma.

Get counts of JSONB properties

I have jsonb column answers which may look like this for a 3 rows:
{answer1: {label: "", value: "answer1_value1"}, answer2: {label: "", value: "answer2_value1"}}
{answer1: {label: "", value: "answer1_value2"}, answer2: {label: "", value: "answer2_value1"}}
{answer1: {label: "", value: "answer1_value2"}, answer2: {label: "", value: "answer2_value2"}}
Answer properties names can be different for a set of rows. I want to get this result(count for each answer grouped by value) from the example above:
answer1: { answer1_value1: 1, answer1_value2: 2}
answer2: { answer2_value1: 2, answer2_value2: 1}
Is it possible?
I got field names like this SELECT DISTINCT json_object_keys(answers::json) as field, but do not know what can I do next.
Use jsonb_each() to be able to count answers and aggregate the results back into a json object:
select jsonb_build_object(key, jsonb_object_agg(val, count))
from (
select key, value->>'value' as val, count(*)
from my_table
cross join jsonb_each(answers)
group by key, val
) s
group by key;
Working example in rextester.

Sequelize (or clear SQL) query for selecting rows what includes value in JSON field?

I have rows in my MYSQL and I Need Sequelize.js query.
Every row have col of type JSON what include this for example:
[
{id: 1234, blah: "test"},
{id: 3210, blah: "test"},
{id: 5897, blah: "test"}
]
I have id and I need to select row what include this id in at least one object in array.
Raw mysql query will be like this:
SELECT * FROM `user` WHERE JSON_CONTAINS(`comments`, '{"id": 1234}');
Simple sequelize example:
const { fn, col, cast } = this.sequelize;
const User = this.sequelize.define('user', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
comments: DataTypes.JSON,
defaultValue: [],
})
User.findAll({
where: fn('JSON_CONTAINS', col('comments'), cast('{"id": 1234}', 'CHAR CHARACTER SET utf8')),
})
.then(users => console.log('result', users.map(u => u.get())))
.catch(err => console.log('error', err));
Cast function is used to unescape double quotes around "id" to avoid wrong query string like this:
SELECT * FROM `user` WHERE JSON_CONTAINS(`comments`, '{\"id\": 1234}');
There is one more dirty mysql query example (don't use it):
SELECT * FROM `user` WHERE `comments` LIKE '%"id": 1234%';

Postgres PLpgSQL JSON SUM

I'm trying to calculate the sum of some JSON values in PLpgSQL (Postgres v9.5.5) but am stuck on the logic.
For this data set:
{
clientOrderId: 'OR836374647',
status: 'PENDING',
clientId: '583b52ede4b1a3668ba0dfff',
sharerId: '583b249417329b5b737ad3ee',
buyerId: 'abcd12345678',
buyerEmail: 'test#test.com',
lineItems: [{
name: faker.commerce.productName(),
description: faker.commerce.department(),
category: 'test',
sku: faker.random.alphaNumeric(),
quantity: 3
price: 40
status: 'PENDING'
}, {
name: faker.commerce.productName(),
description: faker.commerce.department(),
category: 'test',
sku: faker.random.alphaNumeric(),
quantity: 2,
price: 30,
status: 'PENDING'
}
I am trying to get the subtotal of all the lineItems for each row (i.e. quantity * price for each line item, then the sum of these values for the row). So for the above example, the returned value should be 180.
I got this far, but this is returning the totals for all lineItems in the table, not grouped by row.
WITH line_items AS (SELECT jsonb_array_elements(line_items) as line_items FROM public.order),
line_item_totals AS (SELECT line_items->>'quantity' AS quantity, line_items->>'price' AS price FROM line_items)
SELECT (quantity::int * price::numeric) AS sub_total FROM line_item_totals;
I'm sure the fix is simple but I'm not sure how to do this with JSON fields.
Please always include Postgres version you are using. It also looks like your JSON is incorrect. Below is an example of how you can accomplish this with json type and valid json document.
with t(v) as ( VALUES
('{
"clientOrderId": "OR836374647",
"status": "PENDING",
"clientId": "583b52ede4b1a3668ba0dfff",
"sharerId": "583b249417329b5b737ad3ee",
"buyerId": "abcd12345678",
"buyerEmail": "test#test.com",
"lineItems": [{
"name": "name1",
"description": "desc1",
"category": "test",
"sku": "sku1",
"quantity": 3,
"price": 40,
"status": "PENDING"
},
{
"name": "name2",
"description": "desc2",
"category": "test",
"sku": "sku2",
"quantity": 2,
"price": 30,
"status": "PENDING"
}]
}'::JSON)
)
SELECT
v->>'clientOrderId' cId,
sum((item->>'price')::INTEGER * (item->>'quantity')::INTEGER) subtotal
FROM
t,
json_array_elements(v->'lineItems') item
GROUP BY cId;
Result:
cid | subtotal
-------------+----------
OR836374647 | 180
(1 row)