Playing Next Lesson In
seconds

Transcript

  1. So now that we have our user profile relationship defined within our models, and we have actual records created making use of this relationship, how do we go about querying it?

  2. Well, there's a few different ways we can actually go about this. So let's go ahead and clear our terminal out and node is ripple to jump into a ripple session. We'll await load models,

  3. and let's do const user equals await models user find or fail the user with the ID of one. We'll go ahead and hit enter for that.

  4. And now we should have our user just like so. And there's a few things that we can do with this user. So first we could do related to reach for any relationships

  5. based off of this particular user instance. And here we just define the relationship name. So within the model, we've called this relationship profile. That's the declare property that we defined.

  6. And now we can do dot query to access the query builder for the profile related to this particular user record. Meaning that if we just ran this with just the query builder there, Oh, hold on a minute.

  7. I forgot to await that. Let's jump back up and let's await the results. There we go. That looks a little bit more right. So real quick, whenever we did not await, we actually got a lot back. So we got relationship information,

  8. parent model information, client options, all of that fun stuff, preloader information, essentially defining the underlying query that Lucid would have to build to get to the underlying result for the relationship.

  9. And right here, you can see the model that we're intended on querying itself, which is our profile class, contains key information, the column definitions on that model,

  10. relationship definitions, hooks, so on and so forth. So if you do not await, it won't actually run the query, but it will instead just return back information about the model itself.

  11. And in that case, we were working with a relationship, so it was returning back relationship information as well. But since we've awaited this one, now all that we get back is the underlying relationship

  12. record that we had intended on querying. And you'll notice that we just get back one result here because we only have one profile that belongs to this individual user record.

  13. If we go ahead and run OYO on this so that we can actually see the properties on the profile model that we're querying, you'll see it has the user ID of one, which matches our user's ID

  14. that we're using to query the profile with. So essentially this approach here is building out for us await models.profile.query.where user ID is one.

  15. And it's using the relationship information that we've defined on both of these models to grab the primary key from the user that we're using to query from,

  16. and bind that in to the appropriate where statement for the underlying query builder via the relationship that we are working with. If we were to add OYO to this and run it, you'll see that we get back the exact same result

  17. because both the underlying queries that ran are the same. Another thing that we can do is we can load the relationship directly onto the user record itself.

  18. So we can await user.load, and then specify the relation that we wanna load. In this case, that would be our profile. And this approach here is called lazy loading because we already have a reference to our user record.

  19. And we just want to lazily load the profile relationship onto this record. So if we hit enter here, we get back undefined because nothing was returned. However, if we now do user.profile,

  20. we actually have our profile model directly available to work with. And you'll see all of the original information directly on here. And it looks just like a typical model,

  21. meaning that we can also do user.profile.description, and voila, there's our profile description just like so. Now this user profile isn't available

  22. until we either lazy or eager load the relationship in. For example, if we do const another user

  23. equals await models.user.findOrFail, and we provide an ID of two so that we have a different user here. Let's go ahead and run that.

  24. And now if we do another user.profile, we're going to get back undefined. But if we await another user.loadProfile,

  25. we've now lazily loaded the profile information onto another user.profile. So we can hit up twice and look at that. There's our profile information for our user with an ID of two.

  26. So that approach is referred to as lazy loading, but what about eagerly loading? Well, that's where we start with our user already having the profile information populated. Okay, so I've gone ahead and jumped

  27. into a fresh REPL session and reloaded our models just to clear everything out here. And now what we can do to eager load a relationship onto our user without having to lazily load it in later on

  28. is we can make use of the query builder. So if we do const user equals await models user.query to get access to the user query builder,

  29. we'll do where ID is one to get the user with an ID of one. And then we'll use a method called preload to preload a relationship onto the returned user result.

  30. So if we do profile here, and let's just grab the first or fail record. We'll hit enter there. And now we should have access immediately to user profile, just like so, awesome.

  31. What's really nice about this approach is that we can quickly eager load relationships on multiple records. So we can do const users equals await models user query.

  32. And if we just preload our profile here without specifying a where to hone this down at all, and we just run this query here, we now have all of our users in this variable users,

  33. which in our case should be five. So if we access the first index, we now have our first user record inside of our array dot profile.

  34. We now have direct access to our first user's profile. And if we switch this index from zero to one, there's our second user's profile, third, fourth, and fifth.

  35. And then lastly, we don't have a sixth user. So that one's going to be defined, awesome. And we can chain off of this direct properties as well to get direct access to them.

  36. So whenever we're preloading using the query builder, that's referred to as eager loading. And whenever we take a user record and load onto it, this is referred to as lazy loading.

Querying Relationships and Eager Vs Lazy Loading

@tomgobich
Published by
@tomgobich
In This Lesson

We'll learn how we can query our relationships using our Lucid Models. We'll then learn what the difference is between eagerly loading a relationship (load) and lazily loading a relationship (preload).

Join the Discussion 4 comments

Create a free account to join in on the discussion
  1. is there a risk of an n+1 issue when using lazy loading? ( first comment btw :) )

    1
    1. Responding to laariane-amine
      @tomgobich

      Hi laariane, great question!! Yes, n+1 is still possible, though unlike with other ORMs that offer auto lazy loading by reference since the loading is explicit with Lucid the n+1 issue becomes a little easier to spot.

      For example, here's a n+1 query using Lucid's lazy loading

      const movies = await Movie.all()
      
      for (let movie of movies) {
        // will loop through each movie and 
        // individually query each movie's director
        await movie.load('director')
      }
      Copied!

      This n+1 can be solved by switching to preloading or querying a list of directors rather than individually loading.

      const movies = await Movie
        .query() // still queries all movies since we aren't filtering at all
        .preload('director') // loads director info without n+1
      Copied!
      1
      1. Responding to tomgobich

        thanks for the reply, wouldn't it be better to use "preload" every time in this case to avoid any n+1 issues?

        1
        1. Responding to laariane-amine
          @tomgobich

          When working with many records and you can use preload, like in the example provided above, yes!

          0