How latestOfMany() Makes Grabbing the Newest Record Easy in Eloquent

How latestOfMany() Makes Grabbing the Newest Record Easy in Eloquent

In relational databases you often need to get one "special" related model from hasMany relation. Like latest login for user, current product price or latest status for order. 

Developers usually solve this problem in two ways — by getting the whole relationship and post-processing it with Laravel's collection API or writing a custom subquery to the database. But there is one more solution, a special method latestOfMany() in Laravel, which was meant for this case.

The Inefficient Workarounds

Here are the two common ways developers fetch a single recent related model:

// Approach 1: Loading all orders just to get the last one in PHP memory
$users = User::with('orders')->get();

foreach ($users as $user) {
    $latestOrder = $user->orders->sortByDesc('created_at')->first();
}

// Approach 2: Querying inside the loop (N+1 query bottleneck)
$users = User::all();

foreach ($users as $user) {
    $latestOrder = $user->orders()->latest()->first(); // 1 query per user!
}

The Solution: latestOfMany()

The latestOfMany() method turns a "one of many" relationship into a clean hasOne relationship that can be eager loaded in a single query.

Define it directly on your parent model:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Model
{
    // The traditional HasMany relation
    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }

    // The single latest record relation
    public function latestOrder(): HasOne
    {
        return $this->hasOne(Order::class)->latestOfMany();
    }
}

Now you can eager load latestOrder like any standard relation:

$users = User::with('latestOrder')->get();

foreach ($users as $user) {
    echo $user->latestOrder?->total_amount;
}

Laravel runs two queries total: one for the users, and an efficient subquery join that fetches exactly one order per user.

oldestOfMany() and Custom Columns

Eloquent also provides the reverse method, oldestOfMany(), to fetch the earliest record (e.g., a customer's first order):

public function firstOrder(): HasOne
{
    return $this->hasOne(Order::class)->oldestOfMany();
}

By default, both methods sort by the primary key (or created_at). If you want to sort by a specific date or custom column, pass the column name as the first argument:

// Sort by published_at instead of id/created_at
public function latestArticle(): HasOne
{
    return $this->hasOne(Article::class)->latestOfMany('published_at');
}

Advanced: ofMany() with Constraints

What if we need the latest record which also meets certain business logics, like highest value completed order ?

Then in such cases we can use ofMany() method. It takes the sorting column, aggregate function (MAX or MIN) and a closure to apply any additional criteria:

public function largestCompletedOrder(): HasOne
{
    return $this->hasOne(Order::class)->ofMany(
        ['total_amount' => 'max'],
        function ($query) {
            $query->where('status', 'completed');
        }
    );
}

This above query will gives use customer's order with largest amount which is completed with fast execution and eager-loadable.

Summary

Method Returns Best Used For
latestOfMany() HasOne Most recent login, latest comment, newest status update.
oldestOfMany() HasOne First purchase, initial account setup record.
ofMany() HasOne Filtered single records (e.g., highest bid, latest active plan).

Whenever you need just one item from a collection of related records, don't load it all into memory. Instead, use latestOfMany() or oldestOfMany() so that the filtering can happen more efficiently at the database level.

Thank you for reading this article 😊

For any query, do not hesitate to comment 💬


Previous Post Next Post

Contact Form