Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

NellyTadi's avatar

How to query a Model Relationship only if it exists?

I have a model Survey with a column installer_id which is related to hasOne another model Installation which is related to hasMany another model Assignment.

I want to write a query to fetch all Survey where the installer_id is not null, and where IF an Assignment exists check all the assignments if any status is != 2 ie status = 0 or 1 return the survey.

I tried this query but it does not capture the "if an assignment exists then check the status" part

 $surveys = Survey::whereNotNull('installer_id')
            ->orWhereHas('installation',function ($query) {
                return $query->whereHas('assignments',function ($q){
                    return $q->where('status','!=', 2 );
                });
        })->get();

I also tried to define a hasManyThrough relationship in the model.

    public function assignments()
    {
        return $this->hasManyThrough(Assignment::class,Installation::class);
    }

and then using this query

 $schedulables = Survey::whereNotNull('installer_id')
            ->orWherehas('assignments',function ($query){
                return $query->where('assignments.status','!=', 2 );
            })->get()

Please any suggestions and help would be appreciated

0 likes
5 replies
webrobert's avatar

@nellytadi

this should work... but it's feeling a bit long...

You don't need the if Null.

This says only give me surveys that have an installation that have assignments where the status...


    $surveys = Survey::whereHas('installation', function ($query) {
        return $query->whereHas('assignments', function ($query) {
            return $query->where('status','!=', 2 );
        });
    })->get();

NellyTadi's avatar

@webrobert This only returns surveys with installations, i need it to return all surveys with installer_id but if the survey has $survey->installation->assignment then it should not return the survey if the assignment status is equal to 2.

webrobert's avatar

@nellytadi

hmm. I think what you have should work...

 $surveys = Survey::whereNotNull('installer_id')
            ->orWhereHas('installation', function ($query) {
                return $query->whereHas('assignments', function ($q){
                    return $q->where('status','!=', 2 );
                });
        })->get();

I could be missing something. it's early here.

SilenceBringer's avatar
Level 55

@nellytadi

Survey::whereNotNull('installer_id')
	->whereDoesntHave('installation.assignments', fn ($query) => $query->where('status', 2))
	->get()
1 like

Please or to participate in this conversation.