laravel get all places for all events where place - php

I'm finally learning the Laravel ORM, and quite frankly, it's making me depressed as I'm working against a tight deadline.
I'm trying the simplest thing, easily to achieve in SQL in a few seconds, and after half an hour with the ORM, I just can't get it to work.
1 event has 1 place. In EventModel:
public function place(){
$this->hasOne('zwoop\models\place\PlaceModel', 'place_id');
}
1 place can belong to many events. In PlaceModel:
public function events(){
$this->belongsToMany('zwoop\models\event\EventModel');
}
Now in the EventModel, what is the structure to get all events where place is within certain bounds? (eg. where place.lat > input_lat and lng > input_lng (simplified).
I would give example code, but I can't figure it out at all.
This is just the beginning of a query that is really long, I really wonder if the ORM will be the most efficient solution in the end...

Have you looked at the Querying Relations section of the Laravel Docs?
EventModel::whereHas('place', function($q) {
$q->where('lat', '>', input_lat)
->where('lng', '>', input_lng);
})->get();

Hmm. let me explain here a little bit. There are quite several ways to do it. But the most efficient way should be the following:
Get all places within certain bounds using
$places = Place::where('lat', '>', input_lat)->where('lng', '>', input_lng)->get();
$places = $places->lists('id');
Get all events ids using
Events::whereIn('place_id', $places)->get();
It is done!
Of course you can combine the two and make it one query. Personally I do not like mix queries thought it should give you a little boost in performance in your case.

Related

Get data from one table using one query and filter different rows into separate variables (Laravel 5.1)

I understand the question might not be very clear but here is my situation. I'm using laravel 5 and i'm developing a CRM system. I have placed Marital Status and Sex/Gender into one Lookup table. Whenever i get the values from the database and pass it to the view, i have two separate queries.
$sexes = DB::table('Lookups')
->where('ValueType', '=', 'Sex')->get();`
$marstatus = DB::table('Lookups')
->where('ValueType', '=', 'Marital Status')->get();`
return view('clients.edit',compact('client'))
->with('sexes', $sexes)
->with('marstatus ', $marstatus );
This code actually works and i am able to get both the marital status and sex/gender on my view.
So, here is my question
Doesn't this mean that i am sending a query to the database twice which affects performance even if it is small
Isn't there a way to query all the values from the lookup table in one query and filter out the values on the controller. So it can be something like
$Lookups = DB::table('Lookups')
and then filter the $Lookups variable and assign it into two different variables ($sexes and $marstatus) based on my filter criteria. i.e ($sexes is for values that have ValueType = 'Sex' ...)
Which one is better for performance. Sending a query twice or three times or just filtering the data on the controller.
1) Yes it does. Just install Laravel Debugbar and see it yourself. It's a very handy tool strongly recommended.
2) Yes you can do that, laravel has nice helper functions for that type of needs:
$collection = collect(DB::table('Lookups')
->whereIn('ValueType', ['Marital Status', 'Sex'])
->get());
$marstatus = $collection->filter(function($item) {
return $item->ValueType == 'Marital Status';
});
$sexes = $collection->filter(function($item) {
return $item->ValueType == 'Sexes';
});
What this does is, it converts the result array to a Laravel Collection so that you can use the filter function. You can also use array_filter function to filter without converting the result array to a collection.
3) Databases are always one of the primary bottlenecks, the fewer the query number the better. However this should not be a general rule especially when cache is used. And for example making joins or subqueries to reduce the number of queries would be deadly mistake on some cases.
Performance is a huge subject. I'd recommend you to start with the Laravel Debugbar to compare the memory usage, number of queries etc. and investigate more on various techniques including cacheing and design patterns too. Accessing the tables directly within the controller is not a very good idea in the first place...
Yes it does mean that. How big is your Lookups table?
You probably mean $lookups = DB::table('Lookups')->all(); or perhaps consider using an Eloquent model class instead, e.g. $lookups = Lookup::all(); Perhaps you may want to cache the result if the table is small? e.g. use the Cache classes in Laravel.
Better for performance would be to use the cache.
It is belong to your query Data I mean your lookups table data.
You can write the query like this in one time:
$sexes_marital_status= DB::table('Lookups')->where('ValueType', '=', 'Sex')
->orWhere('ValueType' '=', 'Marital Status' )
->get();
return view('clients.edit',compact('client'))
->with('sexes_marital_status',$sexes_marital_status);
and this is better that you send your query in one time.
`

Query Laravel Result Set

I am looking to do several queries using eloquent which are all to be returned to a single view and was wondering if there was a better way to do it than querying the database multiple times?
For example returning all the records then pulling sub sets of data from that?
At the moment I have something similar to:
$one = User::queryOne();
$two = User::queryTwo();
$three = User::queryThree();
etc
However I was thinking it would be better if it was possible to do something like:
$users = User::all();
$one = $users->where('created_at')...
$two = $users->where('modified_at')..
Obviously the above doesn't work but it it possible to do something like this?
Or is it best just to query the database separately each time?
From a pragmatic point of view, it's 'better' to do multiple queries, because it takes you less time to write them, and they are easier to read and debug. If you want to do it with one DB query, and then grabbing subsets out of them, you'd have to write your own convoluted logic, or perhaps a new Laravel collection class. And then someone else comes along and wonders, "What is going on in this code?"
Typically programmer time is the most constrained resource in a project. When you get done, if you find that the multiple database queries are a bottleneck, then think about re-writing it.
If you do decide to do one query, you can probably order the data by the fields you want for the criteria. Then loop through the result set, adding the rows to a new array each time the specified field's value changes. That's the simplest logic I can think of offhand.
What version of laravel are you using? In 5.1 you can do where on collections here. In 4.2 you can do so with callbacks here
EDIT
for 4.2 try something similar to this
$users = User::all();
$one = $users->filter(function($user)
{
if($user->age > 20){
return true;
}
return false;
});
Laravel Eloquent returns a Collection as a result.
You could use a foreach statement or use the build in Collections functions you could manipulate the results and create the sub-results.
For example you could use filter and do something like this:
$users = User::all();
$one = $collection->filter(function ($item) {
return $item->created_at >= time() - (24*60*60); // created the last day
});
$filtered->all();
Whether it is the best method depends on the application and the amount of data you are trying to fetch/process.
If you have only a few records from ::all(), then doing so might be a good approach (although using the collections functions you have to run three filters across your data).
If you have a lot of records from ::all() then it is preferably to use three different queries to the database (especially if the results will only be a few records).

Laravel Eloquent - Is it inefficient

I'm looking at developing a new site with Laravel. I was reading a tutorial on http://vegibit.com/laravel-eloquent-orm-tutorial/, regarding using Eloquent to join tables and retrieve data. In the last example they are essentially trying to do a join but still Eloquent is executing two queries instead of one. Is Eloquent inefficient or is this simply a poor example? It seems that this could have simply been done with a single left join query. Can anyone provide some insight on this? Is there a better way to execute this query? The specific example is:
Route::get('/', function()
{
$paintings = Painting::with('painter')->get();
foreach($paintings as $painting){
echo $painting->painter->username;
echo ' painted the ';
echo $painting->title;
echo '<br>';
}
});
Results in the following queries:
string ‘select * from paintings‘ (length=25)
string ‘select * from painters where painters.id in (?, ?, ?)’ (length=59)
Leonardo Da Vinci painted the Mona Lisa
Leonardo Da Vinci painted the Last Supper
Vincent Van Gogh painted the The Starry Night
Vincent Van Gogh painted the The Potato Eaters
Rembrandt painted the The Night Watch
Rembrandt painted the The Storm on the Sea of Galilee
Eloquent is extremely useful for building something quickly and also has query caching that it's really easy to use however it might not be ideal for big projects that need to scale over time, my approach is to use Repository pattern with contracts that way I can still use the power of Eloquent and have a system that will allow me to easily change the implementation if needed.
If what you want is to get all the data in a single query to use joins, then you must specify it as:
Painting::join('Painter as p', 'p.IdPainter', '=', 'Painting.IdPainting')->get()
And if you need some conditional then:
Painting::join('Painter as p', 'p.IdPainter', '=', 'Painting.IdPainting')->where('cond1', '=', 'value')->get();
Personally Eloquent is inefficient, i prefer Doctrine in this regard.
The simple answer to your question: No. It is not inefficient.
Using Eloquent in the way described by Jorge really defeats its purpose as an ORM.
Whilst you can write joins as in the example given, an ORM really isn't designed with that in mind.
The example you've given isn't an n+1 query (where there's an additional query run for each item in the loop - the worst type of query).
Using two queries as reported by your output isn't a huge overhead, and I think you'd be fine to use that in production. Your use of Eloquent's 'with' eager loading is precisely what you should use in this context.
An example of an n+1 query (which you want to avoid) is as follows:
foreach (Book::all() as $book)
{
echo $book->author->name;
}
If 20 books are returned by Book::all(), then the loop would execute 21 queries in total. 1 to get all of the books, and 1 for each iteration of $book to get the author's name.
Using Eloquent with eager loading, combined with caching would be enough to minimise any performance issues.

Laravel - Retrieve Entries Starting with "X"

I've been looking around and testing things for about 2 hours now, and I finally figured it's time to reach out for help.
Basically, I want to do an search on a catalog - but only return items starting with a specific letter. I've tried multiple things from raw queries, to trying to bend where() to my liking - but none of the existing methods to achieve this has worked for me yet.
The code is rather simple that I'm working with here.
$var = DB::('table')->where('field', 'LIKE', "%$argument")->get();
$argument is passed via URI (root.com/controller/sort-by/field/$arg). All URI segments print out correctly when dd()'ed. So the proper value is being passed to the query, I would assume? Also if I dd($var), then it populates with the table's entries when I drop out the where() statement.
I've attempted a lot of things here, and nothing is pulling the single entry that I have in the database at the moment...
So, am I'm extremely overlooking something here - or actually tackling this the wrong way?
I swapped my query to
$foo = MODEL::where('#FIELD#', 'LIKE', $arg . '%')->get();
Then I can access the values by enumerating through the returned array. So a foreach will be required, but in general terms.
{{ $foo[0]->field }}
Returns the field value.
Thanks all.

Logic in getting users that is not a member of the group

What kind of logic is behind getting a list of users that is not a member of the selected group.
Or get a list of users that is not in my contacts list.
Using laravel I have came up with a code.
The code:
// I get all the uid of the members of the user group.
$members_list = GroupMembers::where('group_id', $group_id)->lists('uid');
// I compare it to the list of all users and get those that are not in the list
$nonMembers = Users:whereNotIn('uid', $members_list)->paginate(10);
But is this the most efficient way of doing it?
I'm not sure it really matters too much because they are both pretty simple queries so they shouldn't take too long. It would probably take some experimenting to figure out which way is the fastest if you are really concerned about performance.
Here is a way you can do it using the query builder and table joins. This will use one query, but because it's joining, it will probably take just about the same amount of time as using what you have already. Also note that this won't allow you to traverse the collections like you usually would ($user->group->name for example would just become $user->name, which if there is a name column on your users table, something may get overwritten)
$users = DB::table('group_members')
->join('users','users.uid','=','group_members.uid')
->where('group_members.group_id', '<>', $group_id)
->paginate(10);
What you are doing now is pretty much exactly what eager loading is doing, except you are doing it by hand. The correct way to do this is as follows and is probably your best solution, though it probably won't save you anything on performance.
$users = User::with(array('groupMembers' => function($query) use ($group_id)
{
$query->where('group_id', '<>', $group_id);
}))->paginate(10);
definitely not that best..
Assuming the relationship is
Group members->has many->Users
you could to to use joins
DB::table('group_members')
->join('users','group_members.uid','<>','users.uid')

Categories