Get last record on GROUP BY using Laravel & MySql - php

I have two table (users and messages) .. I wrote a query to get all messages that users sent to me or I sent, using JOIN .. to get all the users I have contacted or they did.
as in the code below:
$users = Message::join('users', function ($join) {
$join->on('messages.sender_id', '=', 'users.id')
->orOn('messages.receiver_id', '=', 'users.id');
})
->where(function ($q) {
$q->where('messages.sender_id', Auth::user()->id)
->orWhere('messages.receiver_id', Auth::user()->id);
})
->orderBy('messages.created', 'desc')
->groupBy('users.id')
->paginate();
The problem here is when records grouped, I'm getting the old message not the new one according to its created_at .. So, I want to get the last record of the grouped records.

It seems like it would make more sense to make use of Eloquent's relationships here so that you can eager load the relationships instead of having to use join and group by:
$messages = Message::with('sender', 'receiver')
->where(function ($query) {
$query->where('sender_id', auth()->id())
->orWhere('receiver_id', auth()->id())
})
->orderByDesc('created') // is this meant to be 'created_at'?
->paginate();

Related

How can I select data rows by id in a database query?

I have a database query that needs filtering further. The id needs to match a number in an array I have. For some reason, I can select where using every column except id. Even something as simple as $query->where('users.id', 1); doesn't work. How can I perform a database query by id?
$portfolio_query_array = UserPortfolio::all()->pluck('user_id')
$query = DB::table('users');
$query->select('users.id as user_id','users.user_slug', 'users.social_id', 'users.social_img_update_status', 'users.avatar', 'users.first_name', 'users.last_name', 'users.bio', 'comments.rating', 'user_portfolios.title', 'user_portfolios.description', 'user_portfolios.filepath');
$query->leftjoin('comments', 'comments.comment_to', '=', 'users.id');
$query->leftjoin('user_portfolios', 'user_portfolios.user_id', '=', 'users.id');
$query->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', '=', 'users.id');
$query->where('users.status', 1);
$query->where('users.user_type', 3);
// The below simple query line doesn't work
$query->where('users.id', 1);
// The lines I do want to work also fail.
foreach ($portfolio_query_array as $user_id){
$query = $query + $query->where('users.id', $user_id);
}
Thank you for your help!
First of all, you should take advantage of Eloquent ORM, there is no need to use raw queries unless you have some performance issues or really complex queries.
Assuming you have 3 models User, UserPortfolio, Comment, and all relationships defined, you could do something as simple as this:
$users = User::with('comments', 'portfolio')
->where('status', 1)
->where('user_type', 3)
->whereHas('portfolio')
->get();
In this way, you are getting all users with portfolios which is what I assume you want.
Anyway, if you insist to use a raw query, there whereIn() method is what you need
$portfolio_query_array = UserPortfolio::pluck('user_id')->toArray();
$query = DB::table('users')
->select(
'users.id as user_id',
'users.user_slug',
'users.social_id',
'users.social_img_update_status',
'users.avatar',
'users.first_name',
'users.last_name',
'users.bio',
'comments.rating',
'user_portfolios.title',
'user_portfolios.description',
'user_portfolios.filepath'
)
->leftjoin('comments', 'comments.comment_to', 'users.id')
->leftjoin('user_portfolios', 'user_portfolios.user_id', 'users.id')
->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', 'users.id')
->where('users.status', 1)
->where('users.user_type', 3)
->whereIn('users.id', $portfolio_query_array)
->get();
BTW, why are you doing a leftJoin to user_profile_category_selects if no fields are selected from that table?
In addition, if you are looking for all users that have a portfolio, starting from the whole list of portfolios, wouldn't be better to do a join to portfolios and get only those users having portfolios?
$query = DB::table('users')
->select(
'users.id as user_id',
'users.user_slug',
'users.social_id',
'users.social_img_update_status',
'users.avatar',
'users.first_name',
'users.last_name',
'users.bio',
'comments.rating',
'user_portfolios.title',
'user_portfolios.description',
'user_portfolios.filepath'
)
->leftjoin('comments', 'comments.comment_to', 'users.id')
->join('user_portfolios', 'user_portfolios.user_id', 'users.id')
->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', 'users.id')
->where('users.status', 1)
->where('users.user_type', 3)
->get();

I want to use multiple table use in Advanced Join Clauses

I need some help on my query. I use multiple tables with advanced join clauses but it shows invalid count and both has same value:
$parents = DB::table('users')
->select('users.id','users.full_name', 'users.email', 'users.avatar', 'users.signup_date', (DB::raw('count(children.id) as children_no')), (DB::raw('count(invitations.id) as invitations_no')))
->leftJoin('children', function ($join) {
$join->on('users.id', '=', 'children.userid')
->where('children.is_deleted', '=', 0);
})
->leftJoin('invitations', function ($join) {
$join->on('users.id', '=', 'invitations.user_id')
->where('invitations.is_deleted', '=', 0);
})
->where('users.is_admin', '=', 0)
->groupBy('users.id')
->get();
I think you can solve this problem with basic relationships in Laravel + soft deletes on the invitations and children table.
This will make your query less complex and you have the Laravel benefits.
<?php
$users = User::where('is_admin', false)
->has(['invitations', 'children'])
->withCount(['invitations', 'children'])
->get();
This wil select all none admins, with invitations and children.
Make sure you have soft deletes setup on children and invitations.
The withCount will add a count for the related relations.

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();
}

Laravel Eloquent query get users from another model

I have another table called tableb and it has a user relationship defined through the user_id field.
I want to run a query against tableb where a certain date is within a certain range but then I want to grab the user table associated with that row but I only want it to grab the user if it's not been grabbed yet. I'm trying to do this all in 1 DB query. I have most of it done, but I'm having trouble with the unique part of it.
Here's what I have right now:
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->get();
So right now I have 3 entries in tableB from the same user, and ideally I'd like to only get 1 entry for that user.
How would I go about doing this?
Since you're selecting only users data, just add a groupBy clause in your query.
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get();
You should just add groupBy like this :
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get
Try This Code
App/user.php
public function getrelation(){
return $this->hasMany('App\tableB', 'user_id');
}
In Your Controller
Controller.php
use App/user;
public funtion filterByDate(user $user)
{
$date = '2016-02-01';
$result = $user->WhereHas('getrelation', function ($query) use($date) {
$query->whereDate('tableb.start_date', '>', $date)
->first();
});
}

Laravel - Select only certain columns within a 'hasMany' query

I have a query that currently works, however, it returns significantly more data than what I need.
Query
$alerts = Criteria::with('coordinate', 'alerts')
->where('user_id', '=', Auth::id())
->get();
For example, if I want to only select the viewed column out of alerts, can this be achieved in this query. I've used ::with to harness Laravel's eager loading feature.
Many thanks.
Use a closure to set the SELECT clause on your query:
$alerts = Criteria::with(['coordinate', 'alerts' => function($query)
{
$query->select('id', 'coordinate_id', 'viewed');
}])
->where('user_id', '=', Auth::id())
->get();
Remember to include the foreign keys, so that Eloquent can properly map them for you.

Categories