I am grabbing the related meetings with each Department, hence I would like to have a pagination for each meetings list. I currently have this in my Inertia Middleware to have it available in my frontend:
'auth' => [
'user' => $request->user(),
'departments' => $request->user()
? $request->user()->departments()
->with(['meetings' => fn($query) => $query->paginate(10)]) // paginate meetings per department
->get()
: [],
],
I am expeting a paginate object appended to each of the departments for its meetings, so i can use it in the front end. It is supposed to return something like this:
"departments": [
{
"id": 1,
"department": "Human Resources",
"meetings": [
{ "id": 16, "title": "Junta de prueba", "start_date": "2024-12-09", "end_date": "2024-12-09" },
{ "id": 17, "title": "test", "start_date": "2024-12-09", "end_date": "2024-12-09" },
...
],
"pagination": {
"current_page": 1,
"last_page": 2,
"per_page": 10,
"total": 15
}
}
]
2
Answers
Try mapping the department variable and then paginate the and return the result.
The problem here is with eager loading—you’re trying to use it in a way it wasn’t designed for :). Let me explain what’s happening behind the scenes with eager loading in Laravel.
When you use
with
for eager loading, Laravel does two things:Fetch Parent Models
First, it runs a query to get all the parent models (in this case, departments):
Fetch Related Models with ids from all parent models
Then it runs another query to grab all the related models (meetings), but for all the parent models combined:
This is efficient for loading all related meetings in one go. However, it doesn’t support pagination per department because Laravel is fetching everything in a single query for all the departments. Pagination requires limiting the query with something like:
But eager loading can’t do this for each department individually—it fetches everything in bulk. That’s why what you’re trying to do isn’t possible with eager loading.
Solution 1: Paginate Manually Using
map
Since eager loading doesn’t work for this use case, you can handle pagination manually for each department. Here’s how:
Now, each department gets its own paginated
meetings
list, along with pagination metadata.But… Here’s the Catch (N+1 Query Problem)
This solution works fine if you only have a few departments. But if you have a lot of departments, you’ll run into the N+1 query problem.
Here’s why:
So if you have 100 departments, you’ll run 101 queries. That’s fine for small datasets, but it’s going to hurt performance if you have a lot of departments.
Solution 2: Use SQL Window Functions (Avoid N+1)
If you have a lot of departments, you can optimize this by fetching the first 10 meetings for all departments in a single query using SQL window functions.
Here’s how it works:
SQL Query
ROW_NUMBER()
assigns a rank to each meeting within its department, ordered bystart_date
.rn <= 10
ensures we only get the first 10 meetings for each department.Laravel Implementation for your case
Fetch Departments:
Fetch Meetings with SQL:
Use a raw query to get the top 10 meetings per department:
Group Meetings by Department:
Combine Results:
Now it depends on whether you can afford n+1 query or not.