Laravel How to find models that have a specific latest related model

Laravel 5.3.

The package model has many step models. The step model has status column calls, the type of which is a tiny int and a created_at column. For example, package A has the following steps:

  • October 18 10:00, status 1
  • October 19 09:00, status 2

And, package B does the following:

  • October 19 08:00, status 1
  • October 19 09:00, status 2
  • October 19 10:00, status 3

There are just so many packages, each of which has many steps.

A Last step status is 2 and B is 3

My problem is how to find packages whose last step status is 2? Expected Result: The package set in this example should contain A

I tried to add this to my package model.

 public function steps() { return $this->hasMany('App\Step'); } public function status() { return $this->steps()->latest()->limit(1); } 

and request using

 Package::whereHas('status', function ($q) { $q->where('status', 2); })->get(); 

but cannot get the expected result.

What was not expected, if there is only 1 row in the Packages table, packet B , the expected result is an empty collection. But it returns a collection containing B

I also tried updating the status function in the package model to

 public function status() { return $this->hasOne('App\Step')->latest(); } 

but it still does not work.

So what is the right way? Thank you very much.

+5
source share
2 answers

This is pretty tricky. I could not come up with a solution that you can achieve what you want by doing a single Eloquent request. However, I found a way that gives the result in two stages - for example, query + filter.

But before that, you need to add an area to the Package model:

 public function scopeOfStatus($query, $status) { return $query->whereHas('steps', function($q) use ($status) { $q->where('status', $status); }); } 

Step 1: Write a query that retrieves all packages with at least one step that matches your status:

 $status = 1; $packages = Package::with('steps')->ofStatus($status)->get(); 

Step 2: Filter the result to get only packages that their last step matches your status:

 $packages = $packages->filter(function($package) use ($status) { return $package->steps->last()->status == $status; }); 

The end result is a collection of all packages, in their last step status == 1

0
source

try the following:

 $wantedStatus = 2; $packages = Package::with(['steps', function($query){ $query->latest(); }])->get(); $filtered = $packages->filter(function ($package) use ($wantedStatus) { return $package->stpes->last()->status == $wantedStatus; }); 
0
source

Source: https://habr.com/ru/post/1258489/


All Articles