1

I want to get the first related model. But this works only for the first model in the collection. The 2nd is empty.

I've found this answer, but I didn't find a solution.

How can I only get the first related model?

$querybuilder->with([
    'messages' => function ($query) {
        $query->orderBy("created_at", "DESC");
        $query->limit(1);
    }
]);
Camilo
  • 6,504
  • 4
  • 39
  • 60
Patrick Schocke
  • 1,493
  • 2
  • 13
  • 25

2 Answers2

1

You can use a HasOne relationship:

class Conversation extends Model {
    public function latestMessage() {
        return $this->hasOne(Message::class)->latest();
    }
}

$querybuilder->with('latestMessage');

Be aware that this will still fetch all messages from the database. It then discards the "old" ones.

If you want to improve the performance by really only fetching the latest message, you can use this package I created: https://github.com/staudenmeir/eloquent-eager-limit

The package allows you to apply limit() to the relationship:

class Conversation extends Model {
    use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;

    public function latestMessage() {
        return $this->hasOne(Message::class)->latest()->limit(1);
    }
}
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109
  • I will take a look on the package. The latest approach I’m using now, but I have to create a new query for every model in that collection. And that destroyes my Performance. – Patrick Schocke Dec 11 '18 at 15:00
0

Your with() actually creates several queries, the last query has the limit, hence the behavior (which is correct). you can use \DB::enableQueryLog();, run your query and then \DB::getQueryLog(); to see how the queries are built.

If you instead want to apply a limit to each model item you could fetch all items and iterate over them to fetch one or more related model items

This is not done i sql but in php (laravel collection method), if you need it in sql you could just join your related model and set it up however you want.

This will cause performance issues if you have large amount of data, but if you don't it's quite convenient.

$result = \App\YourModel::all()
    ->map(function ($item) {
        return $item->YourRelatedModel()
            ->orderBy('someField')
            ->first();
    });

I forgot ... the above only returns the related model's items, if you also want the parent model you can

$result = \App\YourModel::all()
    ->map(function ($item) {
        $item->YourRelatedModelName = $item
            ->YourRelatedModel()
            ->orderBy('someField')
            ->first();

        return $item;
    });
Jane
  • 428
  • 3
  • 10