Find the best-selling products (Laravel / eloquent)

Asked

Viewed 445 times

1

In the Table, assuming there is a 'Product' model (whose table is products), an 'Account' model (whose table is accounts), and an N:N relationship between accounts and products, in the Product Table, I am trying to find an elegant way to fetch the 5 best selling products using Eloquent Relationships.

Here’s what I have code for so far:

public function maisVendidos($quantidade)
    {

        $cp = ContaProduto::select('produto_id', DB::raw('count(*) as total'))
            ->groupBy('produto_id')
            ->orderBy('total', 'DESC')
            ->limit($quantidade)
            ->get();

        //inicializa um array de produtos + vendidos
        $produtos = [];

        //para cada ID encontrado, buscar o produto associado
        foreach($cp as $obj) {
            $produto = Produto::find($obj->produto_id);
            array_push($produtos, $produto);
        }

        return response()->json($produtos);
    }

Surely there is a way to relate through models, but I’m not finding in the documentation an easy way to do this.

Someone more experienced can give an idea?

Thank you!

EDIT: The models are:

    <?php namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Categoria;
use App\Item;

class Produto extends Model {

    protected $table = 'produtos';  

    public function itens()
    {
        return $this->belongsToMany('App\Item');
    }

    public function categoria()
    {
        return $this->belongsTo('App\Categoria');
    }

    public function contas()
    {
        return $this->belongsToMany('App\Conta');
    }
}

<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Produto;

class Conta extends Model {

    protected $table = 'contas';
    protected $attributes = array(
            'valor' => 0.0,
            'encerrada' => 0
        );

    public function mesa()
    {
        return $this->belongsTo('App\Mesa');
    }

    public function produtos()
    {
        return $this->belongsToMany('App\Produto');
    }
}

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class ContaProduto extends Model
{
    protected $table = 'conta_produto';
}
  • Put the 3 Models in your question with all fields of the table, you have already done something different ( that even works, no problems regarding having the intermediate model implicit ) so it is difficult to say without seeing the code of models and has a performance problem.

  • Thanks for the answer. I added the three models. I believe that it is not very necessary all the attributes, only the keys that relate these three models, which are following the standards of the Laravel. In other words, product has an id (PK), account has an id (PK) and product account_id (FK) and conta_id (FK).

  • The total field comes from where?

  • Actually the total is just an alias for Count(*). Count will count the grouped records in order by.

1 answer

1


One way would be to search for all id of products in the table conta_produto and use method wherein in search of the array of id returnees, example:

public function maisVendidos($quantidade)
{
    $ids = ContaProduto::select('produto_id', DB::raw('count(*) as total'))
            ->groupBy('produto_id')
            ->orderByRaw('count(*) DESC')
            ->limit($quantidade)
            ->pluck('produto_id');

    $produtos = Produto::whereIn('id', ids)->get();
    return response()->json($produtos);
}

References:

  • Thanks for the answer, it’s the one that got closer than I wanted. I only ask to change the Product::wherein('id', ids) by DB::table('products')->wherein('id', $ids)->get(); because using the model here didn’t work, it has to be query Builder anyway. Thank you!

  • @Gabrielaugusto what is the mistake, because it is to work ! pass the error?

  • @Gabrielaugusto missed a get() in my answer should be this.

  • 1

    Really, that was it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.