SQL Select Join with a limit in Laravel/PHP - php

My original query searched the motherboards, then found images for the motherboards. But now, some of the motherboards do not have any image associated so I want to run one query that can find 20 unique motherboards with images.
Code so far:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->where('images.item_type', '=', 'motherboard')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
I have even tried selecting specific results:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
The problem with the code above is that when I loop through each $newMotherboards, it has duplicates for every image that exists with its ID. I only want to retrieve 20 unique motherboards where they were added the most recently, but have images.
If an item has 5 images and it is one of the recent 20 added, then it will appear five times of my 20 limit.

Distinct version:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->distinct()
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
Groupby version:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->groupby('images.item_type')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();

Related

How to order my query by most duplicates in Laravel?

On my website, users can post images.
Images can have tags.
There's 4 tables for this, the images table, the images_tag pivot table, the tag table, and of course the users table.
A user can have multiple images with the same tag(s).
I can pull up the tags a user has used across all his images with this query:
$userTags = Tag::whereHas('images', function($q) use($user) {
$q->where('created_by', $user->id);
})->get();
However, I want to make it so that I can order these tags based on how frequently a user uses them. In other words, I want to order by duplicates. Is this possible?
To achieve this, you're going to need to join the images_tags and images tables, count the number of tags, and order by those tags.
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->get();
The above query will only work in MySQL if the only_full_group_by option is disabled. Otherwise, you're going to need to either rewrite this to use a sub query, or do the ordering in the returned Laravel Collection. For example:
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->get();
$tags = $tags->sortByDesc(function ($tag) {
return $tag->total;
});
If you want to add this to your user model, per your comment, create a function similar to the following:
public function getMostUsedTags($limit = 3)
{
return Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $this->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->limit($limit)
->get();
}

Get id from laravel array with multiple id's

im trying to fetch multiple Id's from one array for then using it on a query relationship.
This is what I tried:
$following = $user->following;
$followingId = $following->id;
I get this error:
'Undefined property: Illuminate\Database\Eloquent\Collection::$id'
If I log $following, I get the following array, as you can see I'm following 4 different users and I need to get those id's:
local.INFO: [{"id":32,"email":"test#mail.com","username":"test#mail.com","photo":"97dfebf4098c0f5c16bca61e2b76c373","cover_photo":"default-no-image.jpg","last_access":null,"activation_code":null,"is_sponsor":0,"is_admin":0,"displayname":null,"followers_amount":1,"winwins_amount":1,"pivot":{"follower_id":1,"followed_id":32}},{"id":69,"email":"fhamada#paginar.net","username":"fhamada#paginar.net","photo":"placeholder-square.jpg","cover_photo":"default-no-image.jpg","last_access":null,"activation_code":null,"is_sponsor":0,"is_admin":0,"displayname":null,"followers_amount":1,"winwins_amount":0,"pivot":{"follower_id":1,"followed_id":69}},{"id":79,"email":"sandrastun#gmail.com","username":"sandrastun#gmail.com","photo":"placeholder-square.jpg","cover_photo":"default-no-image.jpg","last_access":null,"activation_code":null,"is_sponsor":0,"is_admin":0,"displayname":null,"followers_amount":1,"winwins_amount":0,"pivot":{"follower_id":1,"followed_id":79}},{"id":101,"email":"cristobalalfonzo#outlook.com","username":"cristobalalfonzo#outlook.com","photo":"placeholder-square.jpg","cover_photo":"default-no-image.jpg","last_access":null,"activation_code":null,"is_sponsor":0,"is_admin":0,"displayname":null,"followers_amount":1,"winwins_amount":0,"pivot":{"follower_id":1,"followed_id":101}}]
Query relationship:
$activities = DB::table('notifications')
->join('users', 'users.id', '=', 'notifications.sender_id')
->join('followers', 'followed_id', '=', 'users.id')
->join('user_details', 'user_details.id', '=', 'notifications.user_id')
->join('winwins', 'winwins.id', '=', 'object_id')
->leftJoin('groups', 'notifications.object_id', '=', 'groups.id')
->where('notifications.sender_id', '=', $user->id)
->orWhere('winwins.id', '=', 'notifications.object_id')
->orWhere('sender_id', '=', $user->id)
->orWhere('followers.followed_id', '=', $followingId)
->orderBy('sent_at', 'desc')
->skip($page * $amount)
->take($amount)
To fetch multiple columns from a collection (e.g. multiple IDs from your following collection), use this:
$followingId = $following->pluck('id')->toArray();

Laravel Eloquent - Select MAX with other columns

I'm trying to select a number of columns along with MAX. The raw query would be something like: SELECT users.id, ..., MAX(ur.rank) AS rank but I cannot figure out how to do it using the query builder supplied by Laravel in Eloquent.
This is my attempt:
$user = User::join('users_ranks AS ur', function($join) {
$join ->on('ur.uid', '=', 'users.id');
})
->where('users.id', '=', 7)
->groupBy('users.id')
->first(['users.id', 'users.username', 'MAX(ur.rank) AS rank']);
I simply cannot figure it out. What I want to achieve is I'm selecting a user where users.id = 7, and I'm wanting to select the MAX rank that's in users_ranks where their users_ranks.uid = users.id.
I was told to avoid sub-queries as when working with large result sets, it can slow things down dramatically.
Can anyone point me in the right direction? Thanks.
I think you should rewrite it like this:
DB::table('users')
->select(['users.id', 'users.username', DB::raw('MAX(ur.rank) AS rank')])
->leftJoin('users_ranks AS ur', 'ur.uid', '=', 'users.id')
->where('users.id', '=', 7)
->groupBy('users.id')
->first();
No sense to use User:: if you use table names later and want to fetch not all of the fields ( 'users.id', 'users.username' ).

DISTINCT method using Laravel 5 eloquent query builder

I'm struggling to get unique results when using the DISTINCT method in laravel. This is my query
//Get users that are part of this sector
$users = DB::table('users')->distinct()
->join('projects', 'users.id', '=', 'projects.userID')
->where('projects.sectorID', '=', $sector->sectorID)
->get();
dd($users);
The result shows 3 users with the same ID, when I only want one of them in the results.
How should I change my query?
Try to use group by id
$users = DB::table('users')
->join('projects', 'users.id', '=', 'projects.userID')
->where('projects.sectorID', '=', $sector->sectorID)
->groupBy('users.id')
->get();
dd($users);

How to sort to post by votes in Laravel Queries

how can I sort posts by votes in Laravel Queries? I know how to get the count by using ->count() but I don't know how to integrate it while joining other table.
$posts = DB::table('posts')
->join('votes', 'votes.post_id', '=', 'posts.id')
->select('posts.id', 'posts.description', 'posts.user_id', 'posts.created_at')
->where('posts.created_at', '>=', date('Y-m-d H:i:s',time()-86400))
->paginate(10);
I don't know how to orderBy vote counts.
Assuming you're storing individual votes for each post (one to many):
$posts = DB::table('posts')
->join('votes', 'votes.post_id', '=', 'posts.id')
->select('posts.id', 'posts.description', 'posts.user_id', 'posts.created_at', DB::raw('COUNT(posts.id) AS total')
->where('posts.created_at', '>=', date('Y-m-d H:i:s',time()-86400))
->groupBy('posts.id')
->orderBy(DB::raw('total'), 'desc')
->paginate(10);
Note that Laravel's paginate class is poorly implemented and, when used with a groupBy, might choke on large number of results.

Categories