ChatGPT解决这个技术问题 Extra ChatGPT

Laravel Eloquent groupBy() AND also return count of each group

I have a table that contains, amongst other columns, a column of browser versions. And I simply want to know from the record-set, how many of each type of browser there are. So, I need to end up with something like this: Total Records: 10; Internet Explorer 8: 2; Chrome 25: 4; Firefox 20: 4. (All adding up to 10)

Here's my two pence:

$user_info = Usermeta::groupBy('browser')->get();

Of course that just contains the 3 browsers and not the number of each. How can I do this?


A
Antonio Carlos Ribeiro

This is working for me:

$user_info = DB::table('usermetas')
                 ->select('browser', DB::raw('count(*) as total'))
                 ->groupBy('browser')
                 ->get();

Superb! Just added 'browser' to the select thus: select('browser', ...) and got everything needed. You're good, you! youtube.com/watch?v=ravi4YtUTxo
Thanks. But why doesn't it work when used with Models like User::select('country', DB::raw('count(*) as total')->otherMethods() ?
+v. use \DB instead of DB at controllers
@AmitBera can you explain the reason?, please
Is there any particular reason why you prefer DB::table('usermetas')->.. over Usermeta::.. ?
A
Amit Bera

This works for me (Laravel 5.1):

$user_info = Usermeta::groupBy('browser')->select('browser', DB::raw('count(*) as total'))->get();

M
ManojKiran Appathurai

Thanks Antonio,

I've just added the lists command at the end so it will only return one array with key and count:

Laravel 4

$user_info = DB::table('usermetas')
    ->select('browser', DB::raw('count(*) as total'))
    ->groupBy('browser')
    ->lists('total','browser');

Laravel 5.1

$user_info = DB::table('usermetas')
    ->select('browser', DB::raw('count(*) as total'))
    ->groupBy('browser')
    ->lists('total','browser')->all();

Laravel 5.2+

$user_info = DB::table('usermetas')
    ->select('browser', DB::raw('count(*) as total'))
    ->groupBy('browser')
    ->pluck('total','browser');

Thanks. One note: ->all() in the 5.1 example should be removed, since you already lists the results.
list() is deprecated and renamed to pluck() laravel.com/docs/5.2/upgrade#upgrade-5.2.0
how to sort with total after pluck and take 10 high count from this
i founded tnx usermetas::groupBy('browser') ->selectRaw('count(*) as total, browser') ->orderBy('total','DESC') ->skip(0)->take($number)->pluck('browser');
A
Adam Kozlowski

If you want to get collection, groupBy and count:

$collection = ModelName::groupBy('group_id')
->selectRaw('count(*) as total, group_id')
->get();

Cheers!


J
Jignesh Joisar

Open config/database.php Find strict key inside mysql connection settings Set the value to false


the perfect way to avoid the raw query !!
The perfect way to mess your future sql codes up! And not be able to run it on a standard database without modification.
M
Maik Lowrey

Works that way as well, a bit more tidy. getQuery() just returns the underlying builder, which already contains the table reference.

$browser_total_raw = DB::raw('count(*) as total');
$user_info = Usermeta::getQuery()
    ->select('browser', $browser_total_raw)
    ->groupBy('browser')
    ->pluck('total','browser');

J
Jasim Juwel

Try with this

->groupBy('state_id','locality')
  ->havingRaw('count > 1 ')
  ->having('items.name','LIKE',"%$keyword%")
  ->orHavingRaw('brand LIKE ?',array("%$keyword%"))

While this may answer the question, it is better to explain the essential parts of the answer and possibly what was the problem with OPs code.
Thanks! The havingRaw bit is really nice since it lets you also lets you filter out the results you don't want based on the count. Comes in handy when you want to do some "and-filtering" and have joins for each filter.
T
Tony
$post = Post::select(DB::raw('count(*) as user_count, category_id'))
              ->groupBy('category_id')
              ->get();

This is an example which results count of post by category.


A
Alaksandar Jesus Gene

Laravel Version 8

Removed the dependency of DB

     $counts = Model::whereIn('agent_id', $agents)
        ->orderBy('total', 'asc')
        ->selectRaw('agent_id, count(*) as total')
        ->groupBy('agent_id')
        ->pluck('total','agent_id')->all();

S
Steven

Another way would be this:


$data = Usermeta::orderBy('browser')->selectRaw('browser, count(*) as total')->get()


A
Abe Nalisi

In Laravel 8 you can use countBy() to get the total count of a group.

Check the documentation on the same. https://laravel.com/docs/8.x/collections#method-countBy


This is for Collections and not for Eloquent models. It would be inefficient to get all of the records from the database and then perform a groupby.
m
masud_moni

Here is a more Laravel way to handle group by without the need to use raw statements.

$sources = $sources->where('age','>', 31)->groupBy('age');

$output = null;
foreach($sources as $key => $source) {
    foreach($source as $item) {
        //get each item in the group
    }
    $output[$key] = $source->count();
}

This is memory and processing hungry.
Same memory pb for me
M
Maik Lowrey

If you want to get sorted data use this also

$category_id = Post::orderBy('count', 'desc')
    ->select(DB::raw('category_id,count(*) as count'))
    ->groupBy('category_id')
    ->get();

R
Rubens

Simple solution(tested with Laravel 9 and Spatie/Permissions).

Controller:

//Get permissions group by guard name(3 in my case: web, admin and api)
$permissions = Permission::get()->groupBy('guard_name');

View:

@foreach($permissions as $guard => $perm)
  <div class="form-group">
    <label for="permission">Permissions ({{ ucfirst($guard) }}) {{ count($perm) }}</label>
    <select name="permission[]" id="permission" class="form-control @error('permission') is-invalid @enderror" multiple>
      @foreach($perm as $value)
        <option value="{{ $value->id }}">{{ $value->name }}</option>
      @endforeach
    </select>
    @error('permission')
      <div class="invalid-feedback">
        {{ $message }}
      </div>
    @enderror
  </div>
@endforeach