skip to Main Content

I have a classroom model with a hasMany students relationship. I want to check if every classroom has students in one query with eloquent builder. I dont want to retireve the student count either. The has function filters the classrooms that doesn’t have students:

//Classroom model

class Classroom extends Model
{
    public function students(): HasMany
    {
        return $this->hasMany(Student::class);
    }
}

Tried with:

Classroom::has('students')->get();

But it only returns the models with students, not what I want. Expected result:

[
    {
        "has_students": false
    },
    {
        "has_students": false
    },
    {
        "has_students": true
    },
    {
        "has_students": true
    },
    {
        "has_students": false
    }
]

4

Answers


  1. You can do it with:

    AppModelsClassroom::withCount('students')->get()->mapWithKeys(fn ($classroom) => [$classroom->id => ['has_studends' => $classroom->studends_count > 0]]);
    

    That is, use Eqloquent to join classrooms table with the count of students in each classroom, and then map the results with your condition.

    Login or Signup to reply.
  2. Try adding has_stuents attribute accessor

    use IlluminateDatabaseEloquentCastsAttribute;
    ...
    
    protected function hasStudents(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => $this->students->count > 0;
        );
    }
    
    Login or Signup to reply.
  3. As a follow up to Amade’s answer, we now have a withExists method for just checking existence of relationships. So you should be able to do something like this:

    Classroom::withExists('students')->get();
    

    Then, each Classroom object will have a property (attribute) named students_exists (I believe based on the documentation). You could alias this to has_students if you would like:

    Classroom::withExists('students as has_students')->get();
    

    I have not tested this, but based on the documentation this should be what you are looking for.

    If you want that specific structure of data returned you can do what Amade demonstrated with the mapWithKeys method or use a transformer (API Resource).

    Laravel 10.x Docs – Eloquent – Relationships – Other AggregateswithExists

    Login or Signup to reply.
  4. You can add a "hasStudents" method to the Classroom model that uses the "exists" method to check if there are any students associated with the class. Here’s an example code to do that:

    class Classroom extends Model
    {
        public function students(): HasMany
        {
            return $this->hasMany(Student::class);
        }
    
        public function hasStudents(): bool
        {
            return $this->students()->exists();
        }
    }
    

    Then, to get the array of objects with the "has_students" property that indicates whether each class has students, you can run a query to retrieve all classrooms and use the "map" method to create the desired array:

    $classrooms = Classroom::all();
    $classroomData = $classrooms->map(function ($classroom) {
        return [
            'has_students' => $classroom->hasStudents()
        ];
    });
    

    Finally, you can convert $classroomData to JSON using the "toJson" method:

    $jsonData = $classroomData->toJson();
    

    This will produce the desired JSON array with the "has_students" property for each class.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search