I have three tables (details omitted for brevity):
create table products (
id,
name
)
create table tags (
id,
name
)
create table product_tags (
product_id,
tag_id
)
These tables are populated as follows:
--------
products
--------
+----+------+
| id | name |
+----+------+
| 1 | Rice |
| 2 | Bean |
| 3 | Milk |
+----+------+
----
tags
----
+----+-------+
| id | name |
+----+-------+
| 1 | Eat |
| 2 | Drink |
| 3 | Seeds |
| 4 | Cow |
+----+-------+
When fetching products I want the output to be formatted as:
[{
id: 1,
name: 'Rice',
tags: [
{
id: 1,
name: 'Eat'
},
{
id: 3,
name: 'Seeds'
},
]
},
{
id: 2,
name: 'Bean',
tags: [
{
id: 1,
name: 'Eat'
},
{
id: 3,
name: 'Seeds'
},
]
},
{
id: 3,
name: 'Milk',
tags: [
{
id: 2,
name: 'Drink'
},
{
id: 4,
name: 'Cow'
},
]
}]
To accomplish this, what I'm doing is:
select
products.*,
tags.id as tag_id, tags.name as tag_name
from products
left join product_tags map on map.product_id = products.id
left join tags on map.tag_id = tags.id
The output of which is:
[{
id: 1,
name: 'Rice',
tag_id: 1,
tag_name: 'Eat',
},{
id: 1,
name: 'Rice',
tag_id: 3,
tag_name: 'Seeds',
},{
id: 2,
name: 'Bean',
tag_id: 1,
tag_name: 'Eat',
},{
id: 2,
name: 'Bean',
tag_id: 3,
tag_name: 'Seeds',
},{
id: 3,
name: 'Milk',
tag_id: 2,
tag_name: 'Drink',
},{
id: 3,
name: 'Milk',
tag_id: 4,
tag_name: 'Cow',
}]
Which I parse by hand and aggregate each product instance with an array of zero or more tag objects that it is associated with.
Question
When doing the select above, the output is 6 rows. However, there are only 3 products. Is it possible to use a limit clause that would apply to just the products?
For example, if Product.id => 1 had 10 tags associated with it, doing a LIMIT 5 would only select 5 of the tags. What I want to do is select 5 products along with all tags associated with it.
The only way I can think of achieving this is to select just the products, then do an unbounded SELECT with just the product IDs from the previous query.
Bonus question
Is there a more efficient way to do this JOIN such that the output is aggregated as above?