What Is the Syntax for Sorting an Eloquent Collection by Multiple Columns

What is the syntax for sorting an Eloquent collection by multiple columns?

sortBy() takes a closure, allowing you to provide a single value that should be used for sorting comparisons, but you can make it a composite by concatenating several properties together

$posts = $posts->sortBy(function($post) {
return sprintf('%-12s%s', $post->column1, $post->column2);
});

If you need the sortBy against multiple columns, you probably need to space pad them to ensure that "ABC" and "DEF" comes after "AB" and "DEF", hence the sprint right padded for each column up to the column's length (at least for all but the last column)

Note that it's generally a lot more efficient if you can use an orderBy in your query so the collection is ready-sorted on retrieval from the database

Sorting collection 2 times

Create a multi dimension array, with points being the the first key and victory being the second key, php will automatically sort them key wise.

<?php 
//each array with (Teams, Points, Wins)
$rank[] = array('Team' => "A", 'Points' => 24, 'Wins' => 11);
$rank[] = array('Team' => "B", 'Points' => 26, 'Wins' => 11);
$rank[] = array('Team' => "C", 'Points' => 25, 'Wins' => 10);
$rank[] = array('Team' => "D", 'Points' => 24, 'Wins' => 12);
$rank[] = array('Team' => "E", 'Points' => 25, 'Wins' => 11);
$rank[] = array('Team' => "F", 'Points' => 27, 'Wins' => 13);

foreach ($rank as $key => $row) {
$points[$key] = $row['Points'];
$wins[$key] = $row['Wins'];
}

array_multisort($points, SORT_DESC, $wins, SORT_DESC, $rank);

echo "<ol>";
for ($line = 0; $line < 6; $line++){
echo "<li><b> Rank</b>";
foreach($rank[$line] as $key => $value){
echo "|".$key."-".$value."|";
}
echo "</li>";
}
echo "</ol>";
?>

laravel - how to sort by different columns (first integer and then string)

Use ORDER BY sort_order, title, its equivalent in Laravel being:

$parts = \App\DevicePart::with('device')
->orderBy('sort_order')
->orderBy('title')
->get();

How can i sort an laravel eloquent query by one-to-many relation

I solved this problem:

First off all add a hasOne relation to Product model:

public function latestInventory()
{
return $this->hasOne(Inventory::class);
}

Then in ProductController:

$products = Product::with(['latestInventory' => function($query) {
$query->where('count', '>', 0)->orderBy('id');
}]);
$products = $products->get();
$products = $products->sortBy('latestInventory.price')->paginate(16);

return $products->values()->toArray();

For Paginate the collection :

In ASP (AppServiceProvider.php) on boot method:

Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});

In app/Support/Collection.php:

<?php

namespace App\Support;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;
class Collection extends BaseCollection
{
public function paginate($perPage, $total = null, $page = null, $pageName = 'page')
{
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
}
}

Laravel - Sort array by string value first and then date

Few solutions:

  1. Use a custom callback and return an array source
$products->sortBy(function($product) {
return [$product->param1, $product->param2];
});

This will sort a collection by param2 first, and then by param1


  1. Use a custom callback and return a composite property to sort on source
$posts = $posts->sortBy(function($post) {
return sprintf('%-12s%s', $post->column1, $post->column2);
});

  1. Sort your array by column 1, then split it up by column 2 and then merge it again (untested).
$collection->sortByDesc('date');
$collection->groupBy('status');
$collection->keyBy('status');

EDIT: Also I'm not sure if sortByDesc('date') works with date strings.

Laravel - sorting an array of collections by the property of their relationship object

First of all: Instead of using Collection::groupBy() you can just use relations:

$magazines = Magazine::with(['issues' => function($query) {
$query->orderBy('date', 'desc');
}]);

This will give you a collection of Magazines including related issues in an array. The issues array is sorted by date desc.

Now you can split the result using two queries with different conditions:

$baseQuery = Magazine::with(['issues' => function($query) {
$query->orderBy('date', 'desc');
}]);

$query1 = clone $baseQuery;
$query2 = clone $baseQuery;

$query1->whereIn('product_code', $productCodes);
$query2->whereNotIn('product_code', $productCodes);

$query1 will return all magazines with product_code from the array. $query2 will return all the other magazines.

You have now two ways to combine the two results:

1) Use Eloquent::unionAll()

$unionQuery = $query1->unionAll($query2);
$magazines = $unionQuery->get();

2) Use Collection::merge()

$magazines1 = $query1->get();
$magazines2 = $query2->get();
$magazines = $magazines1->merge($magazines2);

In both cases you will get the same result: A collection of magazines. The magazines with product_code from the $productCodes array are sorted first. Every Magazine object contains an array issues with related Issue objects.

If you want to get rid of the Magazine objects and really need the result to look like in your question, you can still do:

$issues = $magazines->keyBy('id')->pluck('issue');

But there is probably no need for that.

Update

If you really need the two parts of the Magazine collection to be sorted by the latest Issue.. I don't see any way without using a JOIN or sorting in PHP with a closure. Sorting magazines with a join would also need an aggregation. So i would switch back to your original query extending it with a join and split it in two parts as showed above:

$baseQuery = Issue::join('magazines', 'magazines.id', '=', 'issues.magazine_id');
$baseQuery->orderBy('issues.date', 'desc');
$baseQuery->select('issues.*');

$query1 = clone $baseQuery;
$query2 = clone $baseQuery;

$query1->whereIn('magazines.product_code', $productCodes);
$query2->whereNotIn('magazines.product_code', $productCodes);

And then

$issues1 = $query1->get()->groupBy('magazine_id');
$issues2 = $query2->get()->groupBy('magazine_id');

$issues = $issues1->union($issues2);

or

$issues = $query1->unionAll($query2)->get()->groupBy('optionGroupId');

Laravel Eloquent: How to order results of related models?

You have a few ways of achieving this:

// when eager loading
$school = School::with(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}])->find($schoolId);

// when lazy loading
$school = School::find($schoolId);
$school->load(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}]);

// or on the collection
$school = School::find($schoolId);
// asc
$school->students->sortBy('whateverProperty');
// desc
$school->students->sortByDesc('whateverProperty');

// or querying students directly
$students = Student::whereHas('school', function ($q) use ($schoolId) {
$q->where('id', $schoolId);
})->orderBy('whateverField')->get();


Related Topics



Leave a reply



Submit