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;
});
Related
Let's say I have Account and Product models. And I need to get all accounts with favorite products. $alert is boolean to get products with stock alerts. (just an example)
I want to get all accounts having at least one favorite product with alert and all their other favorite products. I am doing this:
...
$query = Account::where('active', true)->when($alert, function ($query) {
$query
->whereHas('products', function($query) {
$this->getThosesWithAlerts($query);
});
});
...
// get $query and make pagination...
I get column not found Account.id in my function "getThosesWithAlerts". I use this function in another query and it works perfectly.
When I use "with" only like:
...
$query = Account::where('active', true)->when($alert, function ($query) {
$query
->with(['products' => function($query) {
$this->getThosesWithAlerts($query);
}]);
});
...
// get $query and make pagination...
I have no error: I have accounts with only products with stock alert (not all); the pagination is broken, so it seems $query is not good for my pagination which works also for another query. It is global pagination for all projetcs queries.
What I want is all products of accounts for accounts having at least one product in alert. Adding with to whereHas in my initial request does not change anything to my error. Unknown column or not found column account.id. So whereHas is my issue but I need it.
...
$query = Account::where('active', true)->when($alert, function ($query) {
$query
->with('products')
->whereHas('products', function($query) {
$this->getThosesWithAlerts($query);
})
});
...
// get $query and make pagination...
what is wrong with whereHas and how to fix it?
I currently have this which works for querying a relationship:
$users = User::query();
$post_id = $request->input('post_id');
$users->whereHas('posts', function ($query) use ($post_id) {
$query->where('id', $post_id);
});
return $users->get();
But in the results of this query I would also like to include Users that do not have any posts connected to them. So the result becomes: users without posts + users with a specific post (code above). Is this possible?
Use doesntHave():
$users->whereHas('posts', function ($query) use ($post_id) {
$query->where('id', $post_id);
})->orDoesntHave('posts');
I have a model "Project" that belongsToMany sites and each site belongsTo a single Locality and each locality belongsTo a single State.
On the other hand I have a user that belongsToMany States
I want to list the projects that are in the same state as the user, so ...
$user = Auth::getUser();
$userStates = array();
foreach($user->profile->states as $singleState){
$userStates[] = $singleState->id;
}
Project::with(['sites','locality','state'])
->whereHas('state', function($q) use($userStates) {
// Query the name field in status table
$q->whereIn('id', $userStates); // '=' is optional
})
I am using OctoberCMS which is built on laravel, However I keep getting an error that says:
Call to undefined method October\Rain\Database\QueryBuilder::state()
The following should get you the projects limited to the authenticated user's states:
$projects = Project::with(['sites.locality.state' => function ($query) {
$query->whereIn('id', auth()->user()->profile->states->pluck('id')->toArray());
}])->get();
update
This should not return projects without a site:
$projects = Project::whereHas('sites.locality.state', function ($query) {
$query->whereIn('id', auth()->user()->profile->states->pluck('id')->toArray());
}])->get();
here is link to my database schema:
How can I get all topics from the blogs to which the user is subscribed using his id? I use Eloquent ORM.
I have added the following lines to my User model:
public function blogs()
{
return $this->belongsToMany('Blog', 'blog_subscriptions');
}
And then requested in the controller
User::find(1)->blogs; // User id is hardcoded
With that I got all blogs to which the user is subscribed.
And now I am stuck on how to get the topics of those blogs.
Assuming relations:
// User
belongsToMany('Blog', 'user_subscriptions')
// Blog
belongsToMany('User', 'user_subscriptions')
hasMany('Topic')
// Topic
belongsTo('Blog')
1 My way, that will work with any relation, no matter how deeply nested:
User::with(['blogs.topics' => function ($q) use (&$topics) {
$topics = $q->get()->unique();
}])->find($userId);
2 Eloquent standard methods:
$topics = Topic::whereHas('blog', function ($q) use ($userId) {
$q->whereHas('users', function ($q) use ($userId) {
$q->where('users.id', $userId);
});
})->get();
// or
$user = User::find($userId);
foreach ($user->blogs as $blog)
{
$blog->topics; // collection of topics for every single blog
}
3 Joins:
$topics = Topic::join('blogs', 'topics.blog_id', '=', 'blogs.id')
->join('user_subscriptions as us', function ($j) use ($userId) {
$j->on('us.blog_id', '=', 'blogs.id')
->where('us.user_id', '=', $userId);
})->get(['topics.*']);
Mind that last solution will rely on your pivot data consistency. That said, if you can't be sure, that there are no redundant entries in user_subscriptions (eg. blog or user has been deleted but the pivot entry remains), then you need to further join users as well.
I am new to laravel and I don't have the possibility of test this, but I had a similar need and solved it with something like this:
DB::Query('topics')->join('blogs', 'blogs.id', '=', 'topics.blog_id')
->join('blog_subscriptions', 'blogs.id', '=', 'blog_subscriptions.blog_id')
->select('name.id','table.email')
->where('blog_subscriptions.user_id', '=', $user_id);
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();