CairoCoder
CairoCoder

Reputation: 3189

Laravel Group By relationship column

I have Invoice_Detail model which handles all products and it's quantities, this model table invoice_details has item_id and qty columns.

The Invoice_Detail has a relation to Items model which holds all item's data there in its items table, which has item_id, name, category_id.

The Item model also has a relation to Category model which has all categories data in its categories table.

Question: I want to select top five categories from Invoice_Detail, how?

Here's what I did:

$topCategories = InvoiceDetail::selectRaw('SUM(qty) as qty')
    ->with(['item.category' => function($query){
        $query->groupBy('id');
    }])
    ->orderBy('qty', 'DESC')
    ->take(5)->get();

But didn't work !!

[{"qty":"11043","item":null}]

Upvotes: 4

Views: 12150

Answers (1)

Yury
Yury

Reputation: 109

Category::select('categories.*',\DB::raw('sum("invoice_details"."qty") as "qty"'))
        ->leftJoin('items', 'items.category_id', '=', 'categories.id')
        ->leftJoin('invoice_details', 'invoice_details.item_id', '=', 'items.id')
        ->groupBy('categories.id')
        ->orderBy('qty','DESC')
        ->limit(5)
        ->get();

This will return you collection of top categories. Tested on laravel 5.5 and PostgreSQL.

UPD: To solve this without joins you can add to Categories model this:

public function invoiceDetails()
{
    return $this->hasManyThrough(Invoice_Detail::class, Item::class);
}

And to select top 5 categories:

$top = Category::select()->with('invoiceDetails')
    ->get()->sortByDesc(function($item){
        $item->invoiceDetails->sum('qty');
    })->top(5);

But first solution with joins will work faster.

Upvotes: 1

Related Questions