Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ifarooq's avatar

Laravel Eloquent limit and offset is being added automatically to count query

Laravel Eloquent limit and offset is being added automatically to count query.

Limit and offset is being added automatically to my following query although I am not adding any limit and offset into it.

$total_trashed_records=$query_records_trashed->onlyTrashed()->count();

Below is are my queries.

$fields=["id", "first_name","last_name","username","user_type","job_title","status"];

      $query_records = User::select($fields)
          ->Where('first_name', 'like', '%' .$s. '%');
       
   $query_records_trashed=$query_records;

   $total_records=$query_records->count();
        $records=$query_records->orderBy($sort_column, $sort_order)
                               ->skip($page*$rows_per_page)
                               ->take($rows_per_page)
                               ->get();
    
  $total_trashed_records=$query_records_trashed->onlyTrashed()->count();

Below is the result of last query in query log.

   "query" => "select count(*) as aggregate from `users` where `first_name` like ?  and `users`.`deleted_at` is not null limit 50 offset 0"
    "bindings" => array:1 [
     
      0 => "%%"
     ]
    "time" => 0.67
0 likes
4 replies
rodrigo.pedra's avatar

You are: when calling the ->skip() it will add the OFFSET and when calling the ->take() it will add the LIMIT.

The confusion might be because the query builder mutates itself instead of returning new instances.

I commented what happens

// creates a new query builder
$query_records = User::select($fields)
    ->Where('first_name', 'like', '%' .$s. '%');

// not a copy but a reference to same instance
$query_records_trashed=$query_records;

// this will run the query and would not be affected by
// the subsequent calls
$total_records=$query_records->count();

// as you call skip and take before the get method
// it mutates the query object
$records=$query_records->orderBy($sort_column, $sort_order)
    ->skip($page*$rows_per_page)
    ->take($rows_per_page)
    ->get();


// $query_records_trashed is already muted from
// the above statement skip, take, ...
$total_trashed_records=$query_records_trashed->onlyTrashed()->count();

One solution is to clone the query before adding new scopes:

$query_records = User::select($fields)
    ->Where('first_name', 'like', '%' .$s. '%');

$query_records_trashed=$query_records;

$total_records=$query_records->count();


// there is no clone method to chain
// so we use the cloneWithout 
$records=$query_records
    ->cloneWithout([]) // clones the query builder so we don't mutate the original
    ->orderBy($sort_column, $sort_order)
    ->skip($page*$rows_per_page)
    ->take($rows_per_page)
    ->get();

$total_trashed_records=$query_records_trashed
    ->cloneWithout([]) // optional if it won't be used later in the code
    ->onlyTrashed()
    ->count();
ifarooq's avatar

@RODRIGO.PEDRA - I have tried this but same result.

$records=$query_records
    ->cloneWithout([]) // clones the query builder so we don't mutate the original
    ->orderBy($sort_column, $sort_order)
    ->skip($page*$rows_per_page)
    ->take($rows_per_page)
    ->get();

$total_trashed_records=$query_records_trashed
    ->cloneWithout([]) // optional if it won't be used later in the code
    ->onlyTrashed()
    ->count();
rodrigo.pedra's avatar

Hmm, it clones the outer Eloquent\Query but keeps the same inner Query\Builder

Well you could try cloning the Builder directly:

$records = (clone $query_records)
    ->orderBy($sort_column, $sort_order)
    ->withoutTrashed()
    ->skip($page*$rows_per_page)
    ->take($rows_per_page)
    ->get();

$total_trashed_records = (clone $query_records)->onlyTrashed()->count();

Or initiate a new query in the total count:

$records = $query_records
    ->orderBy($sort_column, $sort_order)
    ->withoutTrashed()
    ->skip($page*$rows_per_page)
    ->take($rows_per_page)
    ->get();

$total_trashed_records = User::onlyTrashed()->count();
cvairlis's avatar

Check to do:

$total_records = $query_records->getQuery()->getCountForPagination();

Please or to participate in this conversation.