2

I have places and locations tables. Place could have many locations. Location belongs to Place.

Place: id title

Location: id place_id floor lat lon

class Location extends Model {

    public function place()
    {
        return $this->belongsTo('App\Place');
    }

}

And

class Place extends Model {

    public function locations()
    {
        return $this->hasMany('App\Location');
    }

}

And i need to find places, that belongs only to 1st floor. select * from places inner join locations on places.id = locations.place_id where locations.floor = 1

How does it should be done in Eloquent?

Is something similar to Place::where('locations.floor', '=', 1)->get() exists?

Yes, i know there is whereHas:

Place::whereHas('locations', function($q)
{
    $q->where('floor', '=', 1);
})->get()

but it generates a bit complex query with counts:

select * from `places` where (select count(*) from `locations` where `locations`.`place_id` = `places`.`id` and `floor` = '1') >= 1
3
  • What's the problem with the query that it's generating through the whereHas? Commented May 15, 2015 at 15:10
  • the problem is that it's strange query with aggregate count() function. maybe, just maybe, that behind the engine mysql translate this to simple join (or join to this, i really don't know). is it equal to join method, that i provide? Commented May 16, 2015 at 0:11
  • The thing is, with Laravel a join doesn't happen until it needs to happen. It performs the most efficient request possible at each step. In this case, since a join isn't required, a join isn't performed and a count() is done instead. If you're just wanting to do this for the sake of efficiency, you're either over-optimizing or you shouldn't be using Eloquent as it is extremely slow and resource-heavy. Commented May 16, 2015 at 13:52

3 Answers 3

0

does not this works?

class Location extends Model {

    public function place()
    {
        return $this->belongsTo('App\Place');
    }

}

$locations = Location::where('floor', '=', 1);
$locations->load('place'); //lazy eager loading to reduce queries number
$locations->each(function($location){ 
    $place = $location->place
    //this will run for each found location 
});    

finally, any orm is not for database usage optimization, and it is not worth to expect nice sql's produced by it.

Sign up to request clarification or add additional context in comments.

3 Comments

1 location -> 1 place. So this code provide me only one place, not all from 1st floor.
loop through $locations, i used first() just for demo purposes. ` $locations->each(function($location){ $place = $location->place });`
yes, i understand that i can loop, but it's a bit complex for this simple operation. but thank you for the answer, i think that i will use your approach... mine confuses me =(
0

I haven't tried this, but you have eager loading and you can have a condition:

$places = Place::with(['locations' => function($query)
{
    $query->where('floor', '=', 1);

}])->get();

Source

1 Comment

sadly, it doesn't work, this code means that you grab all places, but load relations only for those, which on 1st floor.
0

Try this :

Place::join('locations', 'places.id', '=', 'locations.place_id')
->where('locations.floor', 1)
->select('places.*')
->get();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.