I'm in need of help of figuring out how to get withCount() to work with nested relationships.
I have so far tried this
return CharityArea::with('campaigns.sponsor', 'campaigns.charityArea', 'campaigns.charityDetail')->withCount('campaigns.users')->where($matchTheseThings)->get();
Basically, I want to get the count of the users in the campaigns model.
The relationship on the CampaignsModel looks like this:
public function users(){
return $this->hasMany('App\UserPreferences', 'campaign_id', 'id');
}
The relationship to campaigns in CharityArea looks like this
public function campaigns(){
return $this->hasMany('App\Campaigns', 'charity_area_id', 'id');
}
Laravel throws and error saying that 'campaigns.users' is not found.
Any ideas on how else to do this?
Thanks.
You can use first set a ManyThrough relation in your CharityArea model.
function users()
{
return $this->hasManyThrough('App\UserPreferences', 'App\Campaigns');
}
Then you can call withCount() on it:
return CharityArea::with('campaigns.sponsor', 'campaigns.charityArea', 'campaigns.charityDetail')
->withCount('users')
->where($matchTheseThings)
->get();
Related
Hello i have below query
Deal::with(array('deal_category'=>function($query){
$query->select('name as dealcategory');
}))->get()
when i try to retrieve dealcategory it does not return any value. I have defined relationship in model like
Deal Model
public function deal_category()
{
return $this->belongsTo('App\DealCategory', 'deal_category_id', 'id');
}
And Deal category model like
public function deals(){
return $this->hasMany('App\Deal','deal_category_id');
}
can anyone help how can i get categoryname?
You have to select the primary key to retrieve the necessary results.
Deal::with(array('deal_category'=>function($query){
$query->select('id', 'name as dealcategory');
}))->get()
Use facade DB.
You can try something like this:
DB::table('deal as d')
->join('deal_category as dc', 'd.id', '=', 'dc.deal_id')
->select('d.name as dealname', 'dc.categoryname')
->get();
So i got an section people can make comments and give like to those comments.
i want to organizate the comments based on how many likes does it have.
so i use something like this
$art = Article::with('category')
->with(array('comments' => function($comments){
//i get the comments related to the article and the count of likes it has
$comments->with('likesCount');
}))
->find($id);
this is the model
<?php
class Comment extends Eloquent {
public function likes()
{
return $this->hasMany('CommentsLike','comment_id');
}
//here i take the count of likes, if i use ->count() it throw
public function likesCount()
{
return $this->likes()
->groupBy('comment_id')
->selectRaw('comment_id,count(*) as comment_likes');
}
}
how can i sort my comment based on what i got in likesCount
Use orderBy() to likesCount() function.
public function likesCount()
{
return $this->likes()
->groupBy('comment_id')
->selectRaw('comment_id,count(*) as comment_likes')
->orderBy('comment_likes', 'desc');
}
In Laravel I have a model that looks like this:
class Recipient extends Model
{
public $table = 'recipients';
public function location()
{
return $this->belongsTo('App\Location');
}
public function teams()
{
return $this->belongsToMany('App\Team');
}
public function company()
{
return $this->belongsTo('App\Company');
}
}
To query that model I do this:
$recipients = Recipient::with('location')
->with('teams')
->where('company_id',Auth::user()->company_id)
->where('teams.id', 10)
->get();
On doing so, I get an error saying that laravel can't find teams.id, as it is only querying the parent recipient table. Wondering what I'm doing wrong, I thought the with method was to eager load / inner join records? Do I need to use a DB: inner join instead? Or am I missing something?
Use the whereHas method for this:
Recipient::with('location')
->where('company_id', auth()->user()->company_id)
->whereHas('teams', function($q){
return $q->where('id', 10);
})
->get();
try being explicit and add a select statement. Sometimes a relationship does not show up when not selected. Include the IDs else it won't work
I have 3 models
User
Channel
Reply
model relations
user have belongsToMany('App\Channel');
channel have hasMany('App\Reply', 'channel_id', 'id')->oldest();
let's say i have 2 channels
- channel-1
- channel-2
channel-2 has latest replies than channel-1
now, i want to order the user's channel by its channel's current reply.
just like some chat application.
how can i order the user's channel just like this?
channel-2
channel-1
i already tried some codes. but nothing happen
// User Model
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved')
->with(['replies'])
->orderBy('replies.created_at'); // error
}
// also
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved')
->with(['replies' => function($qry) {
$qry->latest();
}]);
}
// but i did not get the expected result
EDIT
also, i tried this. yes i did get the expected result but it would not load all channel if there's no reply.
public function channels()
{
return $this->belongsToMany('App\Channel')
->withPivot('is_approved')
->join('replies', 'replies.channel_id', '=', 'channels.id')
->groupBy('replies.channel_id')
->orderBy('replies.created_at', 'ASC');
}
EDIT:
According to my knowledge, eager load with method run 2nd query. That's why you can't achieve what you want with eager loading with method.
I think use join method in combination with relationship method is the solution. The following solution is fully tested and work well.
// In User Model
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved');
}
public function sortedChannels($orderBy)
{
return $this->channels()
->join('replies', 'replies.channel_id', '=', 'channel.id')
->orderBy('replies.created_at', $orderBy)
->get();
}
Then you can call $user->sortedChannels('desc') to get the list of channels order by replies created_at attribute.
For condition like channels (which may or may not have replies), just use leftJoin method.
public function sortedChannels($orderBy)
{
return $this->channels()
->leftJoin('replies', 'channel.id', '=', 'replies.channel_id')
->orderBy('replies.created_at', $orderBy)
->get();
}
Edit:
If you want to add groupBy method to the query, you have to pay special attention to your orderBy clause. Because in Sql nature, Group By clause run first before Order By clause. See detail this problem at this stackoverflow question.
So if you add groupBy method, you have to use orderByRaw method and should be implemented like the following.
return $this->channels()
->leftJoin('replies', 'channels.id', '=', 'replies.channel_id')
->groupBy(['channels.id'])
->orderByRaw('max(replies.created_at) desc')
->get();
Inside your channel class you need to create this hasOne relation (you channel hasMany replies, but it hasOne latest reply):
public function latestReply()
{
return $this->hasOne(\App\Reply)->latest();
}
You can now get all channels ordered by latest reply like this:
Channel::with('latestReply')->get()->sortByDesc('latestReply.created_at');
To get all channels from the user ordered by latest reply you would need that method:
public function getChannelsOrderdByLatestReply()
{
return $this->channels()->with('latestReply')->get()->sortByDesc('latestReply.created_at');
}
where channels() is given by:
public function channels()
{
return $this->belongsToMany('App\Channel');
}
Firstly, you don't have to specify the name of the pivot table if you follow Laravel's naming convention so your code looks a bit cleaner:
public function channels()
{
return $this->belongsToMany('App\Channel') ...
Secondly, you'd have to call join explicitly to achieve the result in one query:
public function channels()
{
return $this->belongsToMany(Channel::class) // a bit more clean
->withPivot('is_approved')
->leftJoin('replies', 'replies.channel_id', '=', 'channels.id') // channels.id
->groupBy('replies.channel_id')
->orderBy('replies.created_at', 'desc');
}
If you have a hasOne() relationship, you can sort all the records by doing:
$results = Channel::with('reply')
->join('replies', 'channels.replay_id', '=', 'replies.id')
->orderBy('replies.created_at', 'desc')
->paginate(10);
This sorts all the channels records by the newest replies (assuming you have only one reply per channel.) This is not your case, but someone may be looking for something like this (as I was.)
In index controller i don't need any condition so data retrieves very clearly with all relational models.
$questions = Question::with('user','courses','subjects')->take(10)->orderBy("id","DESC")->get();
This return the question list with all related data like user courses and subject
But in courses controller when try to retrieve data with same and adding condition for course slug then its return error.
$questions = Question::with('user','courses','subjects')->where("slug",$course)->take(10)->orderBy("id","DESC")->get();
Because its adds this condition in question table query so there are no slug coloumn.
And When i retrieved with course class it return correct result but the subjects and users are missing
$questions = Course::with("question")->where("nick_name",$course)->orWhere("slug",$course)->orderBy("id","DESC")->take(10)->get();
Then how can i get all related data.
And the course model has
public function question(){
return $this->belongsToMany('App\Models\Question','university_questions')->take(10);
}
and question model have
public function courses(){
return $this->belongsToMany('App\Models\Course','course_questions');
}
public function subjects(){
return $this->belongsToMany('App\Models\Subject','subject_questions');
}
public function years(){
return $this->hasMany('App\Models\QuestionYear');
}
What is missing here please help.
if you want to get multiple relations you need to pass array,like this
$questions = Course::with([
'questions.user',
'questions.courses',
'questions.subjects'
])
->take(10)
->where("slug",$slug)
->orderBy("id","DESC")
->get();