Laravel Eloquent Relation Two Model - laravel

I have two model. User, Images. How can I get all the users who has images and the image date is between start and end date. Date column name "date".

You can try using Eloquent whereHas().
So the code should look like:
$users= User::whereHas('images', function($query) use ($start_date, $end_date) {
return $query->where([
['date', > , $start_date],
['date', < , $end_sate],
]);
})->get();
Document: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence
Do not forget to format the date to however you want. Considering using whereDate()/whereBetween() is advised. Just play around till you get it right.

in controller class write a query to fetch all user with who has images and date is between the start and end date
$from = date('2018-01-01');
$to = date('2018-05-02');
$users= DB::table('users')
->join('images', 'users.is', '=', 'images.user_id')
->select('users.*')
->whereBetween('date', [$from , $to])
->distinct('users.id')
->get();

Related

Laravel: Use order by in combination with whereHas

I want to retrieve a collection of data, which is ordered by the start_date of the relation
Basically I want to achieve this, with Laravel Models (the code below works perfectly)
$posts = DB::table('posts')
->leftJoin(
'threads',
'posts.id',
'=',
'threads.postable_id'
)
->where('threads.postable_type', '=', 'App\Post')
->orderBy('threads.start_date')
->paginate($request->input('limit', 2));
So in this case, I'm fetching ALL Posts and those are ordered by the start_date of the thread relation.
Those are not my actual tables but this works perfectly!
Because I'm using https://laravel.com/docs/8.x/eloquent-resources this is not the ideal solution to retrieve sorted data.
So instead I want to use the orderBy clause somewhere here
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now());
});
But I just cannot make this work. I've tried this
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
and I also appended this to the actual relation:
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
If you look at your code:
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
the whereHas will only return Post associate with a thread which the function return true.
Try this:
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
This will fetch all Post with Thread only if they have at least one Thread and then orderBy the start_date of the Thread.
You don't have to do the whereHas function because when you call ->with('thread') it'll use you this :
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
whereHas doesnt retrieve the relationship.
If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment: Laravel whereHas
Don't do :
$posts = Post::with('thread')->orderBy('thread.start_date');
If there is no thread on some post, post without thread will be fetch with value null for their key thread and you will have an unexpected result when you try to orderBy.
First of all I want to thank Elie Morin for his help but I found out that I definitely need to use joins for that task.
In my example, I wanted to order the main query (posts) by the relation's start_date
Doing what you suggested
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
Would only order the thread by start_date and not the ENTIRE query.
Which is why I came up with something like this:
$posts = Post::has('thread')
->select('posts.id')
->leftJoin(
'thread',
'posts.id',
'=',
'thread.postable_id'
)
->where('thread.postable_type', '=', 'App\Post')
->where('thread.end_date', '>=', Carbon::now())
->orderBy('thread.start_date')
->with('thread');
return PostResource::collection($posts->paginate(2));

Finding a user with highest post created in last 24 hours, laravel Eloquent

How to find the user with the highest post created in the last 24 hours in laravel?
sorted by the number of posts in descending order.
If I'm not wrong, you are asking for the users with the highest number of posts created in the last 24 hrs.
To accomplish this, do the following:
$users = User::withCount(['posts' => function ($query) {
$query->where('created_at', '>=', carbon()->now()->subDay());
}])->orderBy('posts_count', 'DESC')
->get();
As the documentation states, you can add constraints to the queries.
Counting Related Models
If you want to count the number of results from a relationship without actually loading them you may use the
withCount method, which will place a {relation}_count column on
your resulting models. For example:
$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
You may add the "counts" for multiple relations as well as add
constraints to the queries:
$posts = Post::withCount(['votes', 'comments' => function ($query) {
$query->where('content', 'like', 'foo%');
}])->get();
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;
use Carbon\Carbon;
get user id:
$minusday = Carbon::now()->subDay();
$user_id = DB::table('posts')
->select('user_id', DB::raw('count(id) as total'))
->where('created_at', '>=', $minusday)
->groupBy('user_id')
->orderBy('total','desc')
->limit(1)
->get();
In regular SQL syntax you'd need something like below:
SELECT COUNT(id), user_id
FROM posts
WHERE created_at = today
GROUP BY user_id
ORDER BY COUNT(user_id) DESC
LIMIT 1;
It gets all the posts, groups them by user_id, sorts them with the highest user_id count up top and gets the first record.
I am by no means an expert on SQL, let alone the query builder in Laravel, so someone else would probably be better at writing that.
I know that you can get the posts that were created today by using Carbon, like so:
Post::whereDate('created_at', Carbon::today())->get();
EDIT: This might work for you:
$last24h = Carbon::now()->subDay();
DB::table('posts')
->select(array(DB::raw('COUNT(id)', 'user_id')))
->where('created_at', '>=', $last24h)
->groupBy('user_id')
->orderBy('COUNT(id)', 'DESC')
->limit(1)
->get();
Be sure to include use Carbon\Carbon to be able to use Carbon.
This should give you both the amount of posts and the corresponding user id.

Laravel : Group users by month and output month name

I am querying users created in Laravel by month, here is my code
$devlist = DB::table("users")
->select("id" ,DB::raw("(COUNT(*)) as month"))
->orderBy('created_at')
->groupBy(DB::raw("MONTH(created_at)"))
->get();
This is giving me this
[{"id":1,"month":3},{"id":4,"month":4}]
How can I output the month as well instead of just the word month? So my expected result would be
[{"id":1,"january":3},{"id":4,"febuary":4}]
It's difficult to answer this without seeing the database, but I hope this will help:
$devlist = DB::table("users")
->select(DB::raw('EXTRACT(MONTH FROM created_at) AS month, COUNT(id) as id'))
->orderBy('created_at')
->groupBy(DB::raw('month'))
->get();
$statement = Purchase::selectRaw('monthname(purchase_date) month')
->groupBy('month')
->orderByRaw('min(purchase_date) asc')
->get();
echo "<pre>";
print_r($statement);
die;
Hard to tell without seeing your DB structure, but something like this would be fine. As noted, the output you are showing doesn't line up with the groupBy clause, but assuming the groupBy is correct, this will restructure the way you need:
$devlist = DB::table("users")
->select("id" ,DB::raw("(COUNT(*)) as month"))
->orderBy('created_at')
->groupBy(DB::raw("MONTH(created_at)"))
->get()
->map(function($monthItems, $month) {
return $monthItems->map(function($item) use ($month) {
return [
'id' => $item->id,
$month => $item->month,
];
});
});
Simply use this
\App\Model::selectRaw('monthname(date) as month, sum(total_amount) as total_sale')
->groupBy('month')
->orderByRaw('min(date) desc')
->get();

Laravel Eloquent: how to get related records via whereHas() method?

For example, I can check every post with concrete date.
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
But suppose, what to do, if I want to compare a post model date (created_at) with the date attribute of user model?
For example:
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', ** $user->customDate ** ← look this);
})->get();
upd.
I use Eloquent outside of Laravel.
You can use a raw expression on the Eloquent sub query, by using $q->whereRaw.
In your example:
$users = User::whereHas('posts', function($q){
$q->whereRaw("created_at >= users.customDate");
})->get();
Unlike DB::raw, this can be used without Laravel's dependency injection of Illuminate\Database facade.
Assuming that your users table is just called users you can use DB::raw() to reference a value like you would in a normal query:
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', DB::raw('users.customDate'));
})->get();
Don't forget to either import the DB facade or just change it to \DB::raw(...).
If you're using this outside of Laravel and don't have facades you can cut out the middleman and do:
$q->where('created_at', '>=', new Illuminate\Database\Query\Expression(('users.customDate'));
Hope this helps!

Order by sum column relationship in Laravel

I have this controller which grabs posts from a post table.
Every post in the posts table have the relation "hasMany" with another table likes.
Controller:
public function getDashboard(){
$posts = Post::orderBy('created_at', 'desc')->get();
return view('dashboard', ['posts' => $posts]);
}
I'd like to replace 'created at' with something like:
$post->likes->sum(like)
Don't know how to write the right syntax though.
EDIT:
Here are the tables.
Posts
--id
--body
Likes
--id
--post_id
--like
The column like can have the value 1 or -1.
I'd like to order on the summation of that column for each post.
So a post with one dislike(-1) and one like(1) will have the aggregated value of 0, hence will be placed after a post with one like(1).
You can use withCount() for this as:
Post::withCount('likes')->orderBy('likes_count')->get()
withCount() will place a {relation}_count column on your resulting
models
Update
Post::withCount(['likes' => function($q) {
$q->where('like', 1)
}])
->orderBy('likes_count')
->get()
Update2
You can use sortByDesc() to sort your collection as:
$posts = Post::get();
$posts = $posts->sortByDesc(function ($post) {
return $post->likes->sum('like');
});
If you want to sum column value from relationship and then sort records.
$users = User::addSelect(['likes' => Post::selectRaw('sum(likes) as total_likes')
->whereColumn('user_id', 'useres.id')
->groupBy('user_id')
])
->orderBy('likes', 'DESC')
->get()
->toArray();
Or
use below
$users = User::select("*",
\DB::raw('(SELECT SUM(likes) FROM likes_table WHERE likes_table.user_id = users.id) as tolal_likes'))
->orderBy('likes', 'DESC')
->get()
->toArray();

Resources