Eloquent ORM query to return only models that have specific models in their collections

StackOverflow https://stackoverflow.com/questions/23665382

  •  22-07-2023
  •  | 
  •  

Pregunta

I am struggling to get Eloquent ORM to produce the results I need. I have three models, Job, Phase and Team.

The Job Model

public function phases()
{
    return $this->hasMany('Eloquent\Models\Phase', 'job_id', 'job_id');
}

The Phase Model

public function job()
{
    return $this->belongsTo('Eloquent\Models\Job', 'job_id', 'job_id');
}

public function teams()
{
    return $this->hasMany('Eloquent\Models\Team', 'phase_id', 'phase_id');
}

The Team Model

public function phase()
{
    return $this->belongsTo('Eloquent\Models\Phase', 'phase_id', 'phase_id');
}

When I execute the query

$query = Eloquent\Models\Job::with("Phases.Teams");
$result = $query->get();

I get 40 jobs, which include 50 phases and 75 teams. All Good.

When I execute the query

$query = Eloquent\Models\Job::with(array("Phases.Teams" => function($query)
{
    $query->whereRaw("teams.team_member_quota > 5");
}));

I get a collection with 40 jobs, which include 50 phases and 20 teams. It seems I still get all of the Jobs and Phases, but only the teams have been filtered.

I would like to get a collection of only Jobs that have a team with a team_member_quota > 5, and have within them only Phases that have a team with a team_member_quota > 5, as well as with Phases only have Teams with a team_member_quota > 5.

Is this possible with Eloquent ORM?

¿Fue útil?

Solución 2

This indeed limits the jobs to only jobs that contain teams whose team_member_quota > 5

$query = Eloquent\Models\Job::whereHas('phases', function($query)
{
    $query->whereHas('teams', function ($q) 
    {
        $q->whereRaw("teams.team_member_quota > 5");
    });
});

However, adding the "with" clause

$query->with('phases.teams');

still brings back all the phases for each of those jobs, whether, they contain teams that meet the criteria or not, and all the teams within those phases, whether they have a team_member_quota > 5 or not.

I found this "with" clause worked

$query->with(array(
    "phases" => function($q1)
    {
        $q1->whereHas('teams', function($q2)
        {
            $q2->whereRaw('teams.team_member_quota > 5');
        });
    },
    "phases.teams" => function($q)
    {
        $q->whereRaw("teams.team_member_quota > 5");
    }
));

providing only the phases that contain teams that meet the criteria, and teams that meet the criteria within the results.

Otros consejos

You need whereHas for this, but since it doesn't work with nested relations, you need to nest it manually:

$query = Eloquent\Models\Job::whereHas('phases', function($query)
{
    $query->whereHas('teams', function ($q) {
        $q->whereRaw("teams.team_member_quota > 5");
    });
})
// ->with('phases.teams') // if you still need to load all the relations
;

This will fetch Jobs that have related Phases having Teams with > 5 members (and load all the related models for those jobs as well if you need)


Or define another hasManyThrough relation:

// Job model
public function teams()
{
   return $this->hasManyThrough('Team', 'Phase');
}

// then:
$query = Eloquent\Models\Job::whereHas('teams', function ($q) {
        $q->whereRaw("teams.team_member_quota > 5");
});

For hasManyThrough you need to make sure that all the models have $primaryKey defined, for it seems you don't use default id.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top