Laravel Get Collection for a Collection - laravel

I have 2 models, a User model and a Post model. I am trying to get a collection of Users that have posted between a certain date range. I am just lost on how to tie the 2 models together. There is a One-to-Many relationship between the two.
User Model:
public function posts()
{
return $this->hasMany('App\Models\Post', 'user_id');
}
So, I want a collection of users where posts are between date 1 & date 2 AND if a user has posts between those dates, I want a collection of those posts. I know I can use whereBetween for a query builder, but can I use that for eloquent? Also, how do I sort the entire User model by the ones that have those posts? How about the filter() method?
$users = Users::all();
$users = $users->filter(function() {
foreach ($users as $user)
{
if ($user->posts->whereBetween(date 1, date 2))
{
return true; //something like that
}
}
});

It's better to eager load your relation model as you wanted and then work with the result. no need to use the if checks.
$users = Users::with(['posts' => function($query) {
$query->whereBetween(date 1, date 2);
}])->get();
More Information: Eager Loading

Related

Laravel: How to limit subquery many-to-many when use pivot

I have model IgAccount, which hasMany model IgPost
Then I have model IgHashtag which is connected via pivot table to IgPost
My pivot table is ig_hashtag_ig_post
Now, i want to get all IgHashtag whereHas IgPost which belongsTo user's IgAccount
and I want to also load this with last 4 IgPost, for each IgHashtag
I have query like:
$igHashtags = IgHashtag::with(['igposts' => function ($query) use ($igAccount) {
$query->where('ig_posts.ig_account_id', $igAccount->id) // filter posts for each hashtag, where posts belongsTo hashtag AND only user's ig_account
->select('media_url')
->orderByDesc('from_ig_timestamp');
//->take(4); //Not working as expected, this take 4 posts for whole collection, I need 4 posts for each hashtag
}])->whereHas('igposts', function ($query) use ($igAccount) {
$query->where('ig_account_id', $igAccount->id); //filter only hashtags, which belongsTo posts which belongsTo users ig account
})
->withCount(['igposts' => function ($query) use ($igAccount) {
$query->where('ig_posts.ig_account_id', $igAccount->id);
}])
->orderByDesc('igposts_count')->paginate(10);
This ->take(4) loads 4 posts but for whole collection. In result, one hashtag has 2 loaded posts and another two 2 loaded post, others zero. And I need 4 posts for each hashtag:
0:Object
hashtag:"fotimGalaxy"
id:3578
igposts:Array[1]
igposts_count:44
1:Object
hashtag:"dnesfotim"
id:3576
igposts:Array[2]
igposts_count:30
2:Object
hashtag:"BLINNKER"
id:3762
igposts:Array[0]
igposts_count:13
3:Object
hashtag:"dnesJem"
id:3575
igposts:Array[1]
igposts_count:12
when ->take(4) is removed from code, works as expected, but it load ALL available Posts for each IgHashtag, right filtered:
data:Array[10]
0:Object
hashtag:"fotimGalaxy"
id:3578
igposts:Array[44]
igposts_count:44
1:Object
hashtag:"dnesfotim"
id:3576
igposts:Array[30]
igposts_count:30
2:Object
hashtag:"BLINNKER"
id:3762
igposts:Array[13]
igposts_count:13
3:Object
hashtag:"dnesJem"
id:3575
igposts:Array[12]
igposts_count:12
How to query this with last 4 posts for each hashtags?
Please try this after fixing the names. BTW, it's really a bad idea to give everything the same prefix.
Hastag::with('posts', function($query) {
$query->where('account_id', Auth::id())->latest()->limit(4)
})->get()->filter(function($hastag, $key) {
return $hastag->posts->count() > 0
});
I found solution.
It is not elegant, but it works as expected.
$igHashtags = IgHashtag::whereHas('igposts', function ($query) use ($igAccount) {
$query->where('ig_account_id', $igAccount->id); //filter only hashtags, which belongsTo posts which belongsTo users ig account
})
->withCount(['igposts' => function ($query) use ($igAccount) {
$query->where('ig_posts.ig_account_id', $igAccount->id);
}])
->orderByDesc('igposts_count')->paginate(10);
$igHashtags->getCollection()->transform(function ($value) use ($igAccount) {
$value->igposts = IgHashtag::where('id', $value->id)
->first()
->IgPosts()
->select('caption', 'media_url')
->where('ig_account_id', $igAccount->id)
->orderByDesc('from_ig_timestamp')
->take(4)
->get();
return $value;
});

How to have the sum of a related models column in Eloquent

I have a hasMany relation on my user model
public function timesheet()
{
return $this->hasMany('App\TimeTable', 'employee');
}
and I would like to have the sum of a column
$users = User::select('firstname','lastname')->with('timesheet')->get();
foreach($users as $user) {
//sume of $user->timesheet
//tried $user->timesheet->sum('minutes') which return on each iteration 0
}
What is the best approach to get the right result?
the problem lays on the issue that I use select fileds on User object. On the other hand the sum is really expensive and I get Allowed memory size of 1073741824 bytes exhausted
For the eager loading to work you have to select the users.id column:
$users = User::select('id', 'firstname', 'lastname')->with('timesheet')->get();
If you only fetch the timesheet models for the minutes, you can use a modified withCount():
User::withCount(['timesheet as minutes' => function($query) {
$query->select(DB::raw('sum(minutes)'));
}])->get();
foreach($users as $user) {
$user->minutes
}
Try something along these lines:
$users_with_time = $users->keyBy('id')->map(function($user) {
return $user->sum('timesheets.minutes');
});
It is taking your collection of users, keys them by the user's id and them maps the resultant collection by the sum of the minutes property of the timesheets Eloquent Collection.
You should be left with a Support Collection of total time spent per user id.
I have not had time to test this but it should be a good place to start from.

Laravel, How to retrieve parent records with certain Pivot table values belongsToMany

How can I retrieve all records of my model based on certain ID's in my pivot table?
I have the following 3 tables
users;
id,
name
stats;
id,
name
stats_selected;
user_id,
stats_id
Model
User.php
public function stats()
{
return $this->belongsToMany('App\stats', 'stats_selected', 'user_id', 'stats_id')->withTimestamps();
}
Controller
// Get all users with example of stats ID's
$aFilterWithStatsIDs = [1,10,13];
$oUser = User::with(['stats' => function ($query) use($aFilterWithStatsIDs ) {
$query->whereIn('stats_id', $aFilterWithStatsIDs);
}])
->orderBy('name', 'desc')
->get()
This outputs just all the users. Btw, fetching users with there stats and saving those selected stats into the DB is not a problem. That works fine with the above lines.
But how do I retrieve only the users which has certain stats_id's within them?
But how do I retrieve only the users which has certain stats_id's within them?
Use a whereHas conditional.
User::whereHas('stats', function ($stats) use ($aFilterWithStatsIDs) {
$stats->whereIn('id', $aFilterWithStatsIDs);
});

Filter on related table with Laravel and eloquent

My method is:
public function show(Tag $tag)
{
$posts = $tag->posts;
return view('posts.index',compact('posts'));
}
It works fine but i want to get the posts where posts->user_id is the authenticated user.
public function show(Tag $tag)
{
$posts = $tag->posts()->where('user_id',Auth::user()->id);
return view('posts.index',compact('posts'));
}
How do i filter on the related posts table?
this is a many to many relationship with a pivot table present
What you have should work, but don't forget to get() the results after adding your where:
$posts = $tag->posts()->where('user_id',Auth::user()->id)->get();

Laravel eloquent: get data with model wherePivot equal to custom field

I have an eloquent object Performer that has Albums and Albums have Images
Here is setup:
Model Performer->albums():
public function albums()
{
return $this->belongsToMany('Album','performer_albums','performer_id','album_id');
}
Model Album->images()
public function images()
{
return $this->belongsToMany('Image','album_images','album_id','image_id')->withPivot(['type','size']);
}
I have performer object stored as such:
$performer = Performer::where...->first();
Now I need to get Performer's Albums with images where size is 'large'
So to avoid nesting queries, can I use with()?
I tried
$performer->albums()
->with('images')
->wherePivot('size','large')
->get();
But laravel tells me it's trying to use wherePivot for Performer-Album relationship (M-2-M)
PS. I am also aware that I can do this,
$performer = Performer::with('albums')
->with('albums.images')
->.....-conditions for additional fields in album_images....
->get();
but question remains the same.
You need eager load constraints:
$performer->albums()
->with(['images' => function ($q) {
$q->wherePivot('size','large');
}])
->get();
And btw, no, you can't do this:
Performer::with('albums')
->with('albums.images')
->.....-conditions for additional fields in album_images....
->get();
instead you could do:
Performer::with(['albums.images' => function ($q) {
$q-> .....-conditions for additional fields in album_images....
}])->get();

Resources