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')
Related
I have a scenario like this:
I have User model that has an OneToMany relationships with the Post model.
I have a Hashtag model that has an OneToMany relationships with the Post model.
Recap: ONE user has MANY posts, ONE post belongs to ONE hashtag, ONE hashtag has MANY posts.
I would like to fetch only unique users records of an hashtag.
I'm able to do it in non scalable way (fetching all the posts first and then iterate filtering by user id), but I need to maintain scalability for large record numbers.
Edit: I saw a partial solution in Laravel docs.
Laravel eloquent has a method called unique().
With that method I can specify the parameter which should be unique in query.
In my case figured it out with:
$users = $hashtag->posts->unique('user_id');
But I can't paginate query in this way...
Has anyone a solution for that?
You have to paginate your main model caller.
I don't know exactly if this is can reproduce your actual scenario, but let's see this example:
Let's say you have the model hashtags
So let's say the code could be something like this:
$users = DB::table('hashtags AS tags')
->select('tags.*')
->join('[posts AS post','post.id','=','tags.id')
->distinct()
->paginate(5, ['tags.*']);
I don't know if your query it'll be very accurate, but for this, I believe the best approach it'll be you do a raw query, could look like it'll be costly to your database and the operation, but you can work around this approach indexing and partitioning your database.
Remembering always the eloquent sometimes even when we're building join queries could be more even costly to your database.
Since you're worried about scalability so the best thing could be for too could write a view to fetch all the data with proper indexing and partitioning.
Try to use DISTINCT
$users = $hashtag->posts()->selectRaw('DISTINCT(user_id) AS unique_user_id')->paginate(10);
OR
use groupBy()
$users = $hashtag->posts()->groupBy('name')->select('user_id')->paginate(10);
I am really stuck with this.
I have a Many to Many relationship with Actors and Works. I need to get all the works that don't have all the actors they need. The actors needed per work is a property on the Works table called "extras_needed"
So far I've tried withCount, but you can't use it on a where. This is the closest thing I have which is:
$works = $works->has('actors','<','extras_needed');
But its trying to use extras_needed as a string and I need it to treat it as the column per se.
Any advice? Thanks in advance
You'll want to use DB::raw:
Sometimes you may need to use a raw expression in a query.
Armed with this, we can turn your query into:
$works = $works->has('actors', '<', \DB::raw('extras_needed'));
Hope this helped!
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.
`
I wanted to ask, how can i get data from one table and use this in other find.
For example, i have films table.
I want to get highest rated 3 films. Result should return 3 ID's.
Now, i want to create other query from not associated table, and pass this 3 ID's as "conditions" to find data in other table.
I dont want to use associations, because, data is stored in many databases, and this is problematic.
Thank You.
Once you've got your film IDs you can use in to filter the results from your other Model:-
$filmIds = ['32','55','75'];
$query = TableRegistry::get('Model')->find()
->where(function ($exp, $q) use ($filmIds) {
return $exp->in('film_id', $filmIds);
});
// WHERE film_id IN ('32','55','75')
Check out the docs section on advanced conditions.
If you need to get your film IDs into the correct format (i.e. that shown in the example code) you can use Hash::extract() on the results from your previous query.
if your cakephp version 3.x you can use subqueries in fairly intuitive way
$films = TableRegistry::get('Films')->find('highestRated')
->select(['id'])
->limlt(3);
$query = $related->find()
->where(['id' => $films]);
Subqueries are accepted anywhere a query expression can be used. For example, in the select() and join() methods. http://book.cakephp.org/3.0/en/orm/query-builder.html#subqueries
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.