Search code examples
laravellaravel-5relationships

Filter search results based on data of a relationship in a model


In this scenario, I have Patients Model and Reports Model. where Patients hasMany Reports.

<?php

namespace App;  
use Illuminate\Foundation\Auth\User as Authenticatable;
use DB;
use Spatie\Permission\Traits\HasRoles;

class Patient extends Authenticatable
{
    public function reports()
    {
        return $this->hasMany('App\Reports');
    }
}

In a view, I have a list of all patients with their report ids against them. We have a search patient module where we can search Patient with Patient id and Report id. I am able to satisfy search for Patient id using

$data = Patient::where("id", "LIKE", "%{$search_patient}%")

But could not solve the scenario to search patient and filter results based on Report id, as the data of reports is being retrieved using a hasMany relationship

The below is the result, where Patient data is coming from Patient model and Reports data is coming from Reports model using hasMany relationships. My requirement is when I search with Report id, I should be able to see only data with that report id and user info againt that.

[
  {
    "id": 1,
    "group_id": 1000,
    "date": "01-01-14",
    "name": "Voss",
    "address": "My Home 1",
    "reports": [
      {
        "id": "ABC123",
        "name": "Report1"
      },
      {
        "id": "EDC123",
        "name": "Report2"
      }
    ]
  },
  {
    "id": 2,
    "group_id": 1000,
    "date": "01-01-15",
    "name": "Rosalia",
    "address": "My Home 2",
    "reports": [
      {
        "id": "RTC123",
        "name": "Report3"
      },
      {
        "id": "TYH123",
        "name": "Report4"
      }
    ]
  }
]

Solution

  • Add a belongsTo relationship to your Report model like this:

    public function patient() {
        return $this->belongsTo("App\Models\Patient", "patient_id", "id");
    }
    

    Then perform your search in your Report model

    $data = Report::with('patient')->where('id', $report_id)->get();
    

    The result should look like this

    ...
    {
      "id": ABC123,
      "name": Report 1,
      "patient": {
        "id": 2,
        "group_id": 1000,
        "date": "01-01-15",
        "name": "Rosalia",
        "address": "My Home 2",
      }
    },
    ...
    

    Edit: If you insist to use your patient as base then do this:

     Patient::whereHas('reports', function ($query) use($report_id) {
         $query->where('id', $report_id);
     })->with(['reports' => function ($query) use($report_id) {
         $query->where('id', $report_id);
     }])->get();
    
    1. whereHas will perform the search
    2. with will eager load only the report id you specified