I am making raking system for my users and here's what I have so far:
Get all users and sort them by points - it works fine.
$users = User::all();
$users = $users->sortByDesc(function($item){
return $item->points()->sum('amount');
});
Find your position in ranking - it works fine
$position = 0;
foreach($users as $user){
if(Auth::user()->id == $user->id) break;
$position++;
}
Get myself and users above/under me - it doesn't work. I get random users. It looks like the collection is not sorted anymore.
$myRank = new Collection();
if($position > 9){
$myRank->add($users->get($position-1));
$myRank->add($users->get($position));
$myRank->add($users->get($position+1));
return view('rank.show', ['topTen' => $users->take(15), 'myRank' => $myRank]);
}
Please help me with this one or give some hint on another approach(light weight for many records)
Laravel collection merge() method merge any given array to first collection array. If the first collection is indexed array, the second collection will be added to the end of the new collection. The merge() method can accept either an array or a Collection instance.
I think the problem is this:
When you call User::all()
you get something like this:
0 => points: 10
1 => points: 50
2 => points: 30
3 => points: 70
4 => points: 20
Then you use the sortBy function, which reorder the collection, but does not reset the keys. So you end up with something like this:
3 => points: 70
1 => points: 50
2 => points: 30
4 => points: 20
0 => points: 10
So using position -1, position, and position +1 makes no sense here.
What you can do is using the values() function, which will reset the keys of you collection:
0 => points: 70
1 => points: 50
2 => points: 30
3 => points: 20
4 => points: 10
So I think the following code would work.
$users = User::all();
$users = $users->sortByDesc(function($item){
return $item->points()->sum('amount');
})->values();
And then get 3 users from positions - 1 to position + 1:
$myRank = $users->splice($position - 1, 3);
To sort a collection by key, you can sort the backing array by key then recreate the collection again.
$c = collect(['a' => 1, 'c' => 67, 'b' => 2]);
$items = $c->all();
ksort($items);
$c = collect($items);
Or you can use a macro to get access to the backing array.
Collection::macro('ksort', function(){
//macros callbacks are bound to collection so we can safely access
// protected Collection::items
ksort($this->items);
return $this;
//to return a new instance
//return collect($this->items);
});
The last solution could be very useful if you are going to need to sort collections by key in many places in your code base
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With