cbloss793
cbloss793

Reputation: 1649

Laravel Eager Loading on nested relationship

I have one parent model with a child relationship that I'm trying to order by another relationship with the child.

Plan
-- Items
--- Details

Plan to items is one to many relationship. Items to Details is one to one relationship. I want the Items to be ordered by a field that's set in the details like a title for example. I was thinking that it would look something like in this article.

Plan::with([
  'items.details' => function ($query) {
      $query->orderBy('title', 'asc');
}])
->findOrFail(1);

It doesn't work. I have seen a lot of ways on how to add it to the Parent (Plan) model, but I want to order a relationship--not the parent especially since it's only 1 Plan. I'm sure there is a simple solution, but I can't wrap my mind around it.

Upvotes: 1

Views: 1069

Answers (2)

cbloss793
cbloss793

Reputation: 1649

I don't know if anyone else will run into this issue. The answer that TsailKoga did work, but the collection were interesting. Like the relationships got pushed to parent. For example.

Plan (parent)
-- Items 
--- Details

All the Details attributes became part of the items. It worked but wasn't quite the result I wanted. I tried doing some funky usort, but once you convert a collection to an array to use with usort, you lose all of the tools that goes along with collections/eloquent. I found a way that didn't require anything fancy. Collections have a sortBy method. All I had to do is something like $plan->items->sortBy('details.title') and viola. Plan Items were sorted by title. Days of work for 1 line of code.

I hope this helps someone else out.

Upvotes: 0

TsaiKoga
TsaiKoga

Reputation: 13394

Since the title is from another table details, the items and the details's relationship is one-to-one, you can use leftjoin like this:

Plan::with([
  'items' => function ($query) {
      $query->leftjoin('details', 'details.item_id', '=', 'items.id')
            ->select('items.*', 'details.title')
            ->orderBy('title', 'asc');
}])
->findOrFail(1);

Upvotes: 2

Related Questions