Take first 5 from previous query - laravel

If I have a query like:
$posts = Post::all();
How can I select the first 5 results from that previous query? I tried the following, but it didn't work:
$first_five = $posts->take(5)->get();
Or in other words, how do I get the first 5 elements in the returned object?

I know you can use $first_five = Post::all()->take(5)->get();
I am guessing you may be able to do this also:
$posts = Post::all();
$first_five = $posts->take(5);
Also, have a look into pagination.

Related

How to sort Eloquent collection after fetching results?

In my controller I have this query
$query = Market::whereHas('cities', function($query) use ($city) {
$query->where('id', $city);
})->get();
Then I want to make a few operations with this collection and remove my subquerys from the main object
$return['highlighted'] = $markets->where('highlighted', true);
$markets = $markets->diff($return['highlighted']);
The problem is when I try to sort it by created_at
$return['latest'] = $markets->sortByDesc('created_at')->take(4);
$markets = $markets->diff($return['latest']);
It just won't work, keeps returning the first 4 objects order by id, I've tried parsing created_at inside a callback function with Carbon::parse() and strtotime with no results.
I'm avoiding at all cost to make 2 different database querys since the original $markets has all the data that I need.
Any suggestion?
Thanks
I think your problem is you try to sort and take in one-go and also missing a small thing when you try to access the values of the collection.
Try below approach:
$return['latest'] = $markets->sortByDesc('created_at');
$markets = $markets->diff($return['latest']->values()->take(4));
Or you may need to do it like:
$return['latest'] = $markets->sortByDesc('created_at');
$return['latest'] = $return['latest']->values()->take(4);
$markets = $markets->diff($return['latest']->all());

Laravel Query Builder use multiple times

Is it possible to save a query bulider and use it multiple times?
for example, I have a model 'Tour'.
I create a long query buider and paginate it:
$tour = Tour::where(...)->orWhere(...)->orderBy(...)->paginate(10);
For example, 97 models qualify for the above query.
"Paginate" method outputs first 10 models qualifying for the query, but I also need to so some operations on all 97 models.
I don't want to 'repeat myself' writing this long query 2 times.
So I want something like:
$query = Tour::where(...)->orWhere(...)->orderBy(...);
$tour1 = $query->paginate(10);
$tour2 = $query->get();
Is that a correct way to do in Laravel? (my version is 5.4).
You need to use clone:
$query = Tour::where(...)->orWhere(...)->orderBy(...);
$query1 = clone $query;
$query2 = clone $query;
$tour1 = $query1->paginate(10);
$tour2 = $query2->get();
You can but it doesn't make any sense because every time a new query will be executed. So this code will work:
$query = Tour::where(...)->orWhere(...)->orderBy(...);
$tour1 = $query->paginate(10);
$tour2 = $query->get();
But if you want to execute just one query, you'll need to use collection methods for ordering, filtering and mapping the data. You'll also need to create Paginator instance manually:
$collection = Tour::where(...)->orWhere(...)->orderBy(...)->get();
$tour1 = // Make Paginator manually.
$tour2 = $collection;
$sortedByName = $collection->sortBy('name');
$activeTours = $collection->where('active', 1);

Skip and take all?

In eloquent, how can I skip 10 rows and then get the rest of the table?
User::skip(10)->all();
The above does not work, but it gives you an idea what I am looking for.
Try this:
$count = User::count();
$skip = 10;
User::skip($skip)->take($count - $skip)->get();
With one query:
User::skip($skip)->take(18446744073709551615)->get();
It's ugly, but it's an example from official MySQL manual:
To retrieve all rows from a certain offset up to the end of the result
set, you can use some large number for the second parameter. This
statement retrieves all rows from the 96th row to the last:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
try something like this it work for sure..
$temp = User::count();
$count = $temp - 10;
$data = User::take($count)->skip(10)->get();
Laravel 5 returns Eloquent result as Collection.
So you can use collenction function slice();
$users = User::get();
$slicedUsers = $users->slice(10);

Manual paginator on merged collection

I have a merged collection I want to paginate and I can't seem to figure this out.
First off, the reason I need to create the paginator manually is because I fetch 2 collections first and merge them, like so:
$a = ModelA::all();
$b = ModelB::all();
$c = $a->merge($b);
Next step is to paginate this collection, I tried the Paginator and the LengthAwarePaginator
PAGINATOR
$page = 1;
$results = new Paginator($c, 2, $page);
Here I get the 2 first results in a paginator
$page = 2;
$results = new Paginator($c, 2, $page);
I still get the 2 first results, while i'd expect the third and fourth result (the collection is more then 2 elements long!)
LENGTHAWAREPAGINATOR
$page = 1;
$results = new LengthAwarePaginator($c, count($c), 2, $page);
Here I get a Paginator but the items contain all elements of the collection, no matter what page number i ask for (instead of the 2 i'm asking for)
Any ideas on what might be the problem?
Thank you in advance
According to the Laravel community this is intentional.
You should slice your items before passing it to the Paginator.

Codeigniter Pagination: Run the Query Twice?

I'm using codeigniter and the pagination class. This is such a basic question, but I need to make sure I'm not missing something. In order to get the config items necessary to paginate results getting them from a MySQL database it's basically necessary to run the query twice is that right?
In other words, you have to run the query to determine the total number of records before you can paginate. So I'm doing it like:
Do this query to get number of results
$this->db->where('something', $something);
$query = $this->db->get('the_table_name');
$num_rows = $query->num_rows();
Then I'll have to do it again to get the results with the limit and offset. Something like:
$this->db->where('something', $something);
$this->db->limit($limit, $offset);
$query = $this->db->get('the_table_name');
if($query->num_rows()){
foreach($query->result_array() as $row){
## get the results here
}
}
I just wonder if I'm actually doing this right in that the query always needs to be run twice? The queries I'm using are much more complex than what is shown above.
Unfortunately, in order to paginate you must know how many elements you are breaking up into pages.
You could always cache the result for the total number of elements if it is too computationally expensive.
Yeah, you have to run two queries, but $this->db->count_all('table_name'); is one & line much cleaner.
Pagination requires reading a record set twice:
Once to read the whole set so that it can count the total number records
Then to read a window of records to display
Here's an example I used for a project. The 'banner' table has a list of banners, which I want to show on a paginated screen:
Using a public class property to store the total records (public $total_records)
Using a private function to build the query (that is common for both activities). The parameter ($isCount) we pass to this function reduces the amount of data the query generate, because for the row count we only need one field but when we read the data window we need all required fields.
The get_list() function first calls the database to find the total and stores it in $total_records and then reads a data window to return to the caller.
Remember we cannot access $total_records without first calling the get_list() method !
class Banner_model extends CI_Model {
public $total_records; //holds total records for get_list()
public function get_list($count = 10, $start = 0) {
$this->build_query();
$query = $this->db->get();
$result = $query->result();
$this->total_records = count($result); //store the count
$this->build_query();
$this->db->limit($count, $start);
$query = $this->db->get();
$result = $query->result();
return $result;
}
private function build_query($isCount = FALSE) {
$this->db->select('*, b.id as banner_id, b.status as banner_status');
if ($isCount) {
$this->db->select('b.id');
}
$this->db->from('banner b');
$this->db->join('company c', 'c.id = b.company_id');
$this->db->order_by("b.id", "desc"); //latest ones first
}
And now from the controller we call:
$data['banner_list'] = $this->banner_model->get_list();
$config['total_rows'] = $this->banner_model->total_records;
Things get complicated when you start using JOINs, like in my example where you want to show banners from a particular company! You may read my blog post on this issue further:
http://www.azmeer.info/pagination-hitting-the-database-twise/

Resources