How to add where inside aggregate function in laravel? - laravel

How can I add "where" inside this code?
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->sum('amount_paid');
}])->get();
i'd like to say "with 'loanPayments', sum 'amount_paid' where 'type' is 'payment'.
Thank you so much in advance!

Inside the function, $query is a normal query builder. I think this is what you want:
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->sum('amount_paid');
$query->where('type', 'payment');
}])->get();

Add ->where('type', 'payment')
Select the foreign_key out, and group by foreign_key
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->where('type', 'payment')
->select(DB::raw('SUM(amount_paid) AS sum_amount_paid'), 'loan_application_id')
->groupBy('loan_application_id');
}])->get();

Related

Laravel query orderBy nested relationship

I have the following relationship:
Unit (HasMany)-> Users -> (BelongsTo) -> Position
I am trying to return an array of units with users, where users are sorted by their position. The property in the position model is 'order' that I would like to use as the sort field. I have attempted the following:
return Unit::query()->ordered()->with(['users' => function($query) {
$query->with(['position' => function($query) {
$query->orderBy('order');
}]);
}])->get();
You can not order by nested relationship just using with() method. You need to join the relation first. So the code should be:
return Unit::query()->ordered()->with([
'users' => function ($query) {
$query->join('positions', 'positions.id', '=', 'users.position_id');
$query->orderBy('positions.order');
}
])->get();
or another way is order using laravel collection sortBy
$ordered_units = Unit::query()->ordered()->with(['users' => function($query) {
$query->with(['position' => function($query) {
$query->orderBy('order');
}]);
}])->get();
return $ordered_units->sortBy('users.position.order');

Laravel Eloquent - Filter Relationship of Relationship

This is the query I tried to do:
$products = Product::with(['cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->where('status_id',2)
->get();
I get this results:
In cross_selling I still get id:12 that doesn't has any product_related. I need some help for making that the query doesn't give me that item if product_related is null.
Tks.
First get only those cross selling which has any related products after that get related products. Use the whereHas condition on cross_selling.
$products = Product::with(['cross_selling' => function($qry){
$qry->whereHas('product_related', function ($q) {
$q->where('status_id', 2);
});
}, 'cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->where('status_id',2)
->get();
Try this
$products = Product::with(['cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->has('cross_selling.product_related')
->where('status_id',2)
->get();
If you don't want cross selling products with no related products you can add
->whereHas('product_related')
Which basically says: Get me only cross selling which have 'product_related'.
In order to do it properly, you can:
$callback = fn($query) => $query->where('status_id', 2);
$products = Product::whereHas('cross_selling.product_related', $callback)
->with(['cross_selling.product_related' => $callback])
->where('status_id',2)->get();
Now the callback is applied to the whereHas() and the with() plus you can pass additional constraints using $callback.

Laravel - Filter collection with closure on relationship

Wondering if there is a way to use closure on a relationship in order to filter the whole line if there isn't a value which corresponds?
Example code:
foreach ($paiementMethods as $value) {
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods' => function($query) use ($value)
{
$query->where('id', $value);
}])
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')->get();
$giftCardsCollection = $giftCardsCollection->merge($giftCards);
}
}
In this example, if $query->where doesn't find a row for the payement.payementMethods which matches the $value, I want the giftCard to return null. The result I get is the giftCard with only the relation on payement.payementMethods being empty.
My other solution would be to query the giftCard and after that checking the $value to see if I have to include the giftCard in the collection or not.
Best regards
I think using whereHas, it can be solved
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods'])
->whereHas( 'payement.payementMethods', function($query) use ($paiementMethods) {
$query->whereIn('id', $paiementMethods);
})
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')
->get();

Laravel filter relation's data by other relations data

I am trying to filter my tickets.tips.drawDates relation's data by other relation's column (results.draw_date) in an eager-loading query. Does anybody have any advice on how to accomplish that?
$products = Product::with([
'results' => function ($query) use ($drawDates) {
return $query->whereBetween('draw_date', $drawDates);
},
'tickets' => function ($query) use ($drawDateFrom) {
return $query->whereDate('valid_until', '>=', $drawDateFrom)->where('status', 'pending');
},
'tickets.tips',
'tickets.tips.drawDates' => function($query) {
return $query->whereNull('status')->whereDate('draw_date', 'HERE SHOULD BE draw_date COLUMN FROM results RELATION');
},
'prizes'
])->get();
You could try with the whereColumn() function, it is used to verify that two columns are equal, something like that:
return $query->whereNull('status')->whereColumn('draw_date', 'results.draw_date');

Eloquent - How should I make a condition in a join table

I have a tournament table.
Each tournament hasMany Championships.
I want to get the tournament that match the championshipID = 333.
So, I do it :
$tournament = Tournament::with([
'championships' => function ($query) use ($request) {
$query->where('id', '=', 333);
},
'championships.settings',
'championships.category',
'championships.tree.user1',
'championships.tree.user2',
'championships.tree.user3',
'championships.tree.user4',
'championships.tree.user5'
])->first();
Example of 1 of my relations:
public function settings()
{
return $this->hasOne(ChampionshipSettings::class);
}
Tell me if you need all, to post it.
But as I put 1 eager loading relationship, I get all my tournaments instead of getting just one.
What Am I missing???
I think you're looking for whereHas() which will allow you to filter a model based on a related model's constraints. You should also use a subquery for the nested constraints if you're getting the related model more than once to avoid query duplication like:
$tournament = Tournament::whereHas('championships', function($query) use ($championshipId) {
return $query->where('id', $championshipId);
})
->with(['championships' => function ($query) use ($request) {
$query->where('id', '=', 333)
->with([
'settings',
'category',
'tree' => function($query) {
return $query->with('user1', 'user2', 'user3', 'user4', 'user5');
}]);
}])
->first();

Resources