This episode is for members only

Sign up to access "Mastering Polymorphic Relationships" right now.

Get started
Already a member? Sign in to continue
Playing
08. One to Many: Eager loading and chaperone

Transcript

00:00
So as with all Laravel relationships, we need to be careful with the amount of queries that we're running, particularly if we're iterating in a loop like we are within this example. So what we're going to do is we're actually going to build this example up a little bit further, and we're going to iterate through all articles and show all comments as part of all of them articles.
00:20
We're going to get to the point where we're going to be running way too many queries. We're going to bring in an eager load to solve that, but then we're going to look at how polymorphic relationships are slightly different. So we're going to look at what a chaperone method does to help us here.
00:33
OK, so let's just make sure that our database is in a good state here. So we've got a bunch of comments. We've got two on these articles here. So I think that's OK. Maybe we could just create another one. I'm just going to do this manually in the database.
00:47
So let's say comment four and let's assign that to article one. Great. Now, we should really probably create another article. So let's say another article in here. We'll just make sure we've got a bunch of data that we can get a good result from here.
01:05
So there's another article. Let's go back over to our comments and let's add two more here. So comment five is going to be article two and comment six is going to be article two as well. Great. So what we're now going to do over on our homepage is we are going to iterate over all of the articles instead. So let's say article latest. Yeah. Now, inside of here, we are going to go and iterate on the outer loop of this.
01:42
Say all articles as article. And then we're going to access the comments from the article. In fact, let's go ahead and just keep this really simple for now and just have one single article. We'll look at n plus one and then we'll sort of expand on it from there. So I'm actually going to do here is I am going to keep this, but I'm going to go ahead and just put in a single article for now.
02:10
I will just say article find one. So imagine that you have a slug in the URL. You've used root model binding or whatever to pull this in. So for each article comments as comment, that will show all of the comments we don't need from here because we don't really care. Let's give that a refresh. We've got comment one, two and four.
02:26
OK, so let's dive into our queries and see what we've got here. So we're going to do a composer require on our debug bar to give us a nice debug bar and we can see all of our queries here. Just wait for that to finish. And great. Let's go over and give that a refresh. OK, so let's just take a look at the queries that we've got here. We've only got three.
02:44
Now, if we had some data on each of these comments, like a user, then we would need to go ahead and make sure we egoload this. So let's go ahead and do that now. So let's add in a. User ID in here, you'd obviously do this at the database level, the migration level, but I'm just going to go ahead and manually add this in. I'm going to set that as an unsigned big integer and I'm going to make sure that is nullable for now.
03:12
Yeah, that's fine. We'll just leave it as it is. So for the user ID, let's assign this to my user that I created earlier. And let's go over to the structure and set that back to no. OK, great. So obviously you wouldn't do this, but because I'm just demonstrating without having to recreate the migration, it's a lot easier. So now we have some more data in here. So on the comment itself, we have a user.
03:41
So we're going to say this belongs to. That user. And now what we can do over on the home page is we can say by comment user name. Now we run into an N plus one problem. So this is just basic Laravel stuff, even with the one to many normal relationship. When we're not talking about polymorphic relationships, we would have to egoload this user in because it doesn't make sense to keep querying.
04:11
So to egoload this in, we're going to come over to where we're defining out the article. We're going to say with comments, which we should be doing anyway. So let's just go ahead and give that a refresh. We don't get any lower queries here, but it's a good idea to egoload the comments in anyway for later. Now, with this, we've got a couple of options. We can either drill down and create a closure here to further egoload and order things,
04:34
or we can say just comments.user. So that will egoload comments and it will also egoload user within the comments as well. So now we're down to four queries where all of the users are fetched in one query or the comments fetched in one query. And however many comments and users we add here, it's not going to affect the query count, which is exactly what we want. Now, what happens if we want to further drill down into this and maybe fetch out the commentable type as well?
05:02
So sort of like what we did before and sort of combine this with what we're doing here. So what I'm going to do is I'm going to say article latest. Yeah, I'm going to do exactly the same thing. So I'm going to say with comments.user and we're going to fetch the latest ones out. And then in here, we're going to bring back the outer loop. So we're going to say for each article.
05:23
So imagine you're showing all articles and all comments as part of that article or you're hiding them behind something and you want to output them when user clicks on them, whatever you want to do. So let's go and just test this out by creating an H1 here with the article title. And. Dump out the comments here, but what should we do? Yeah, let's wrap this in a div. And then let's go ahead and wrap this entire thing in a div as well, just to keep everything sort of nice and separate.
05:56
I think that should be OK. Let's go over with that refresh. And yeah, there we go. So we've got the first article which has the two comments and we've got the second article or the first article which has the comments here. Great. So everything looks good at the moment because we're not really doing anything differently. But if we wanted to go ahead and access that commentable relationship, which in our case here, we probably wouldn't need to do, but let's just do it anyway.
06:21
So let's say from comment commentable title and we can use that method that we implemented earlier. Give that a refresh. And there we go. So obviously we wouldn't need to access the article title in this case because we're iterating through them. But if you were iterating through something and trying to access commentable some more information from this, you basically end up back to where you started, where you have an M plus one problem. So obviously we've not got a lot of data here at the moment, but this list is just going to keep growing and growing and growing.
06:52
So what do we do about this? Well, if we come over to any of the models that we define this on. So in our case, we're working with the article. The same thing would work with the episodes as well. We're going to go ahead and use the chaperone method in here. So let's just see the difference this makes when we give this a refresh. So what this will have done is it would have modified the query. So let's just get rid of that.
07:14
Refresh it and it will have gone ahead and it will basically work. It won't modify the query, but it will work out what it needs to pull in based on what we are iterating through here. So when we use chaperone, that gets rid of that sort of overarching M plus one problem when we're trying to access commentable within another loop. So it will just keep all that data together. Now, there's a couple of ways that you could do this.
07:38
If you don't always want to chaperone over on this relationship, you can do this on an individual basis as well. So if we get rid of chaperone here and give that refresh, we're back to five duplicates. What we can do is if you want to do on this on an individual basis, you can do it directly within here. So let's just pull this down. I'm going to go ahead and use query to pull in the query builder to line by line.
07:59
It's just so it's a little bit tidier. And like I said, when we do comments dot user, that means that we're loading in all of the users within this comment. But what we can do is we can say with comments, we can assign this a closure instead. We can either do a long or short closure. I'm going to do a long one here and we get the query directly in here.
08:18
Now, what we can then do is say query with user. Now that puts us back to this stage where we are here, where we are ecoloading the users in. But now what we can do is we can say chaperone on the end of this. So that will just do that on a one off basis rather than apply that to every single relationship that we have in here.
08:38
So rather than do it globally on the comments relationship here, we just do this on a one off basis. It's up to you how you want to do this. It depends, of course, on what you're building and where you're reusing your code. So with these two techniques in mind, you should now be able to iterate through any data that you have polymorphic relationships on. You should be able to access the parent data, but really importantly, without causing an N plus one problem and slowing down your apps.

Episode summary

In this episode, we're diving into one-to-many relationships in Laravel, focusing on how to efficiently fetch related data without blowing up your query count (and, you know, killing your app's performance).

We start by building up a simple example where we have articles and comments. Initially, we're just looping through all articles and displaying their comments, but it quickly becomes apparent that if we're not careful, we're going to run into the dreaded N+1 query problem. To help visualize what's going on, we integrate Laravel Debugbar and keep an eye on the actual queries being run.

Next, we take things a step further by associating users with comments, simulating a typical scenario where each comment is left by a user. This adds another layer to our relationships and, if not handled correctly, increases the number of queries even more. This is where eager loading comes in – we use with() to grab all the related comments and users in one go, massively reducing the number of queries.

Then, the episode tackles polymorphic relationships. We demo how, when accessing the commentable relation (which could be different models, like articles or episodes), the N+1 problem can sneak back in if we aren't careful. That's where the chaperone method comes to the rescue. We explore two ways to use chaperone – globally on a relationship or just for specific queries – so you can keep your app fast no matter how complex your relationships get.

By the end of the video, you'll know how to avoid N+1 issues with one-to-many and polymorphic relationships in Laravel, keeping your code clean and your apps running snappy.

Episode discussion

No comments, yet. Be the first!