Level: Hard — Lets you return ready-to-serve nested JSON from the database, avoiding the N+1 problem in APIs.
Scenario: Your API must return each department with a nested array of its employees as JSON. The naive approach fires one query for departments, then one per department for employees (the N+1 problem). Can you build the entire nested JSON structure in a single query so the API just serves the result?
| dept_id | dept_name |
|---|---|
| 10 | Engineering |
| 20 | Sales |
| emp_id | name | dept_id |
|---|---|---|
| 1 | Rumman | 10 |
| 2 | Krushna | 10 |
| 3 | Manjula | 20 |
-- Wrap each employee row into a JSON object
SELECT JSON_OBJECT('id', emp_id, 'name', name) AS emp_json
FROM employees;
-- {"id": 1, "name": "Rumman"}
-- {"id": 2, "name": "Krushna"} ...
SELECT
d.dept_name,
JSON_ARRAYAGG(
JSON_OBJECT('id', e.emp_id, 'name', e.name)
) AS employees
FROM departments d
JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name;
| dept_name | employees (JSON) |
|---|---|
| Engineering | [{"id":1,"name":"Rumman"},{"id":2,"name":"Krushna"}] |
| Sales | [{"id":3,"name":"Manjula"}] |
One query returns the complete nested structure — no N+1, no app-side stitching.
Why this is powerful: JSON_ARRAYAGG(JSON_OBJECT(...)) collapses the child rows of each group into a single JSON array — exactly the shape a REST/GraphQL API needs. The database does the nesting in one pass instead of the app making N extra queries.
-- Build a single JSON array of departments, each with its employees
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'department', d.dept_name,
'employees', (
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', e.emp_id, 'name', e.name))
FROM employees e WHERE e.dept_id = d.dept_id
)
)
) AS result
FROM departments d;
-- [{"department":"Engineering","employees":[...]}, {"department":"Sales","employees":[...]}]
-- Build a lookup object: { "Engineering": 2, "Sales": 1 } (headcount map)
SELECT JSON_OBJECTAGG(dept_name, cnt) AS headcount_map
FROM (
SELECT d.dept_name, COUNT(e.emp_id) AS cnt
FROM departments d LEFT JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name
) t;
Caveats: JSON_ARRAYAGG does not guarantee element order unless you control it (wrap the source in an ordered subquery). Also watch the group_concat_max_len / max_allowed_packet limits — very large aggregated JSON can be truncated. And duplicate keys in JSON_OBJECTAGG cause an error.
Interviewer follow-up: "Should you build API JSON in the database or the application layer?" → For read-heavy endpoints where it eliminates N+1 round-trips, doing it in SQL is a genuine win. But it couples your DB to your API shape and can strain the DB on huge payloads. A balanced approach: use it for well-bounded nested reads, keep transformation logic in the app for complex/large responses.