@benjamin1509 It should be like this:
public function users()
{
$users = User::where('role', 1)->orderByDesc('wallet_balance')->paginate(20);
return view('admin.users', [
'users' => $users,
]);
}
Hi everyone,
I have defined an accessor that calculates the wallet balance of a user in my User eloquent model. The calculation works fine as expected.
I have a blade view that shows the user's data including the wallet balance from the accessor, but I want to order the result by DESC, meaning the user with the highest wallet balance will show first, and so on.
Example result:
User | Wallet Balance
--------|-----------------
Aaron | 25000
Freek | 14000
Taylor | 7000
Ben | 1000
Here's what I currently have:
Models\User.php
public function getWalletBalanceAttribute(): int
{
$incomes = $this->incomes()->sum('amount');
$withdraws = $this->withdraws()->sum('amount');
$balance = $incomes - $withdraws;
return $balance;
}
public function incomes(): HasMany
{
return $this->hasMany(Income::class);
}
public function withdraws(): HasMany
{
return $this->hasMany(Withdraw::class);
}
Controllers\UserController.php
public function users()
{
$users = User::where('role', 1)->orderByDesc('created_at')->paginate(20);
return view('admin.users', [
'users' => $users,
]);
}
resources\views\admin\users.blade.php
<table>
<thead>
<tr>
<th>User</th>
<th>Wallet Balance</th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td>
{{ $user->name }}
</td>
<td>
{{ $user->wallet_balance }}
</td>
</tr>
@endforeach
</tbody>
{{ $users->links() }}
</table>
@benjamin1509 Ah, I didn’t notice that in the code you’d posted you just did $users->sortByDesc(). That method returns a new collection, so you need to do $users = $users->sortByDesc() instead. I hadn’t paid attention to the pagination either.
The ChatGP* solution will work, but it’s really inefficient – it fetches all users twice in order to get the pagination and the sorting to both work; it generates a long list of specific ID orders to order by in the database (which I suspect will be quite inefficient, though I’m not sure); and it unnecessarily maps over the first collection. It can be done more efficiently by ordering the database result set on the aggregate column names:
$users = User::withSum(['incomes', 'withdraws'], 'amount')
->where('role', 1)
->orderByRaw('incomes_sum_amount - withdraws_sum_amount DESC')
->paginate(20);
This should give you a result set that orders by the wallet balance in descending order and then paginates by 20 – you shouldn’t even need the sortByDesc() call, since the correct ordering is now applied directly in the database.
Note: This won’t work in SQL Server (and perhaps some other implementations), though it does work in MySQL. The upshot is that:
ORDER BY clauses.This means ORDER BY incomes_sum_amount - withdraws_sum_amount results in a syntax error (invalid column names) if you’re using SQL Server.
Please or to participate in this conversation.