I am facing performance issues in Livewire. I am fetching data from a table called “locations.” I have implemented the self-join method on this table. “locations” table contain countries, cities, towns, sub-towns, and blocks.
There is a “parent_id” field in the locations table that is storing the ID of the parent for each row.For example, a city has the “parent_id” of a country and vice versa. Currently, I have data for only one country.
I am querying the “locations” table on the basis of cities and then fetching other towns, sub-towns, and blocks for that city.
The problem I am facing is that it is taking around 6 to 7 seconds to display the list of towns along with their sub-towns and blocks after selecting a city.
this is the function for fetching the data
public function updatedSelectedCity($value)
{
if ($value != NULL || $value != "") {
$city = Location::findOrFail($value);
if ($city) {
$this->lat = $city->lat;
$this->long = $city->long;
$this->dispatchBrowserEvent('load-map', ['lat' => $this->lat, 'long' => $this->long]);
}
$this->state['city_id'] = $value;
$this->towns = Location::where('parent_id',$city->id)->where('level',2)->with('child')
->where('active', 1)->get();
} else {
$this->state['city_id'] = NULL;
$this->state['town_id'] = NULL;
$this->selectedTown = NULL;
$this->state['sub_town_id'] = NULL;
$this->selectedSubTown = NULL;
$this->state['f_s_town_id'] = NULL;
$this->selectedFSTown = NULL;
$this->sub_towns = NULL;
$this->fs_towns = NULL;
$this->towns = NULL;
$this->lat = NULL;
$this->long = NULL;
}
}
Here I am displaying the data in my livewire view.
<div class="col-sm-9 col-md-9 col-lg-9 col-xl-9 col-xxl-9">
<div class="form-group city-group">
<select id="selectTown" style="width: 251px;!important" class=" js-example-basic-single form-control select-box" wire:model="selectedTown">
<option value="" selected>Select a Town</option>
@if($towns)
@foreach($towns as $t)
@forelse ($t->child as $sub_town )
@forelse ($sub_town->child as $block )
<option value="{{$block->id}}">{{$block->name}}, {{$sub_town->name}}, {{$t->name}}</option>
@empty
<option value="{{$sub_town->id}}">{{$sub_town->name}}, {{$t->name}}</option>
@endforelse
@empty
<option value="{{$t->id}}">{{$t->name}}</option>
@endforelse
@endforeach
@endif
</select>
</div>
</div>
This is my model
class Location extends Model
{
use HasFactory;
function parent()
{
return $this->belongsTo(Location::class, 'parent_id');
}
public function child()
{
return $this->hasMany(Location::class, 'parent_id');
}
public static function generateSlug($title)
{
$slug = Str::slug($title);
if (self::whereSlug($slug)->count() > 0) {
$count = 1;
while(self::whereSlug("$slug-$count")->count() > 0)
{
$count++;
}
return "$slug-$count";
}
return $slug;
}
}
I have checked the query execution time it is taking less than a second. So the problem is not with the query. But It is the forelse’s where I am facing speed problem. If I comment the select list part then It work perfectly fine.
<select id="selectTown" style="width: 251px;!important" class=" js-example-basic-single form-control select-box" wire:model="selectedTown">
<option value="" selected>Select a Town</option>
@if($towns)
@foreach($towns as $t)
@forelse ($t->child as $sub_town )
@forelse ($sub_town->child as $block )
<option value="{{$block->id}}">{{$block->name}}, {{$sub_town->name}}, {{$t->name}}</option>
@empty
<option value="{{$sub_town->id}}">{{$sub_town->name}}, {{$t->name}}</option>
@endforelse
@empty
<option value="{{$t->id}}">{{$t->name}}</option>
@endforelse
@endforeach
@endif
</select>
4