Laravel Eloquent request to get products with most categories in common

Viewed 293

Each Product can have several Category

On each product page, I need to display 10 "related products".

To that end, I would like to create a function on the Product model, that would return other products that have the most Category in common, and that would go like so:

public function related_products()
{
  return Product::with('categories')->whereHas('categories',function($query) {
    $query->whereIn('id',$this->category_ids);
  })->take(10)->get();
}

But this would only give me the first 10 products that have at least one category in common.

How can I get the 10 products that have the highest number of categories in common in decreasing order?

The closest I got was this in the internal query:

  $query->whereIn('id',$this->category_ids)
  ->orderByRaw('COUNT(id) desc');

Which isn't working.

2 Answers

You could try the following

  1. Group categories by product id and get count where category ids are in the product's category ids
  2. Order by the count in descending

This will probably require some joins and since table structure is not shown, I can't give any proper code. But hope this gives you an idea on how to do it.

I found a solution that works, since it's not a relationship I'll put it in a Trait and not in the Product Model, I am sure there is a better solution but here is mine anyway:

$related_products = Product::where('id','!=',$base_product->id)
    ->withCount(['categories as common_categories_count' => function($query) use ($base_product) {
        $query->whereIn('id',$base_product->category_ids);
    }])->orderBy('common_categories_count','desc')->take(10)->get();
Related