laravel filter only nested condition - php

I want to filter ONLY nested values in dealTransactions.
In plain English, Merchant wants only dealTransactions have provided dates with Deals.
I tried something like below but it does not work.
dates = ['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05'];
$merchant = Merchant::with(['deals.dealTransactions'])->where('slug', $slug)
->whereHas('deals.dealTransactions', function($query) use ($dates) {
foreach($dates as $date) {
$query->where('date', '=', $date);
}
})
->first();
deal_transactions table
id, deal_id, date
deals table
id, merchant_id,
merchants table
id, many columns for merchant
Thank you

You should be able to do this with a eager load constraint on the nested relationship:
$merchant = Merchant::where('slug', $slug)
->with(['deals.dealTransactions' => function ($query) use ($dates) {
$query->whereIn('date', $dates);
}])->first();

If I understood correctly your schema, this might help:
// Here you define the scope that will be used to select & eager load.
$transactionsScope = function ($q) use ($dates) {
return $q->whereIn('date', $dates);
};
// All merchant of slug in/with that transaction's scope.
$merchant = Merchant::where('slug', $slug)
->whereHas('deals', function ($q) use ($transactionsScope) {
return $q->whereHas('dealTransactions', $transactionsScope);
})
->with(['deals' => function ($q) use ($transactionsScope) {
return $q->with('dealTransactions', $transactionsScope);
}])
->firstOrFail();

Related

Join 2 tables in a Single Eloquent Laravel using multiple where clause

here I'd like to find the solution to simplify my query to get data using eloquent in Laravel.
$room_id = Booking::whereBetween('from', [$request->from, $request->to])
->orWhereBetween('to', [$request->from, $request->to])
->where('from', '<=', $request->from, )
->where('to', '>=', $request->from)
->pluck('room_id');
$rooms = Room::whereNotIn('id', $room_id )->get();
So here I have 2 Eloquent operations to get Rooms which not included in the Booking Table with specified requirements. So far I have no problem with it, but can you guys give me best practice to simplify from what I do? Thank you.
Make sure that 'bookings' relation is written on your Room model.
$rooms = Room::whereDoesntHave('bookings', use($request) function($q){
$q->whereBetween('from', [$request->from, $request->to])
$q->orWhereBetween('to', [$request->from, $request->to])
$q->where('from', '<=', $request->from, )
$q->where('to', '>=', $request->from)
})->get();
Your can refer laravel relationship to add it in model and after that using whereHas to query join table:
https://laravel.com/docs/9.x/eloquent-relationships
Example:
With options
protected $with = [
'product_savour'
];
Relationship
public function product_savour()
{
return $this->hasMany(ProductSavour::class, 'product_id');
}
Query
$productQuery->whereHas('product_savour', function ($query) use ($filters) {
$query->whereHas('savour', function ($query) use ($filters) {
$query->whereHas('type', function ($query) use ($filters) {
$query->whereIn('id', $filters['savour']);
});
});
});

Laravel Eloquent - How Can I Sum fields inside relation's column?

I need to sum every paid_amount inside of each expense_payment_liab instead of returning all these
individual paid_amount as it can be seen in images for clear view.So far my query looks like this:
Model Relation is like Voucher has many Expenses and Expenses has many Expensepaymentliab.
This is so far what I tried:
$expense = Voucher::where('voucher_date', $request->date)
->where('account_id', 1)
->with(['expenses' => function ($expense) use ($date) {
$expense->with(['expPaymentLiab' => function ($inner) use ($date) {
return $inner->select('paid_amount', 'expense_id')->where('paid_date', '=', $date);
//need to return the sum of paid_amount.
// I've also tried this
//$inner->sum('paid_amount')
// $inner->sum('paid_amount', 'expense_id')
}]);
$expense->select('id', 'date', 'total_amount', 'voucher_id');
}])->get();
These are the images please check
Need to sum such paid_amount field.
You can use withCount to sum the paid_amount field.
Voucher::where('voucher_date', $request->date)
->where('account_id', 1)
->with(['expenses' => function ($expense) use ($date) {
// select the columns first, so the subquery column can be added later.
$expense->select('id', 'date', 'total_amount', 'voucher_id');
$expense->withCount(['expPaymentLiab AS paid_sum' => function ($query) use ($date) {
return $query->select(DB::raw('SUM(paid_amount)'))->where('paid_date', '=', $date);
}]);
}])
->get();

Laravel eloquent - Filtering subquery inside with statement

I have the following query:
$countries = Country::where('code', '=', $code)
->with(array('cities.details' => function ($query) use ($user) {
$query->where('cities.name', '=', 'This is a city name');
}))->first();
Lets see the example: I have three tables, Country, City and CityDetails. I want to get all countries, then get all cities (INCLUDING the details information) but I also want to filter cities by name and fetch details table which belongs to the city table.
If I want to use with to get the child and another table using with(cities.details), how can I filter using CITIES attributes?
The main question is: How can I fetch two tables in a with statement like secondTable.OtherTable and filter the query using secondTable attributes?
Just for make it clearer, if I use statement like this:
$countries = Country::where('code', '=', $code)
->with(array('cities.details' => function ($query) use ($user) {
$query->where('name', '=', 'This is a detail name');
}))->first();
I can access only details table attributes. The question is: How can I access the city table attribute to filter inside a with a statement?
Thanks in advance
I just found a solution. Basically, I should apply the filter for city table and then call wit function on the subquery. This code solved my problem:
$countries = Country::where('code', '=', $code)
->with(array('cities' => function ($query) use ($user) {
$query->where('name', '=', 'San Francisco')->with('details');
}))->first();
Note that I called with('details') on city only after filter in subquery.
The most straightforward one is using join query:
(new Country)
->join('cities', 'cities.id', '=', 'countries.city_id')
->join('city_details', 'cities.id', '=', 'city_details.city_id')
->where('cities.name', 'TheName')
->where('city_details.info', 'info')
->select('...');
But the result has only one level. So,
$query = (new Models\Country())
->with([
'cities' => function ($query) {
$query->where('name', 'xxx')->with([
'details' => function ($query) {
$query->where('info', 'info');
}
]);
}
]);
$result = $query->get()->filter(function ($item) {
return count($item['cities']);
});
The result gives countries with empty cities. So use Laravel collection to filter in the last.

OrderBY On model relationship eloquant on controller?

I am not able to find any perfect solution for it.
Controller:
$servicerequest = ServiceRequest::selectRaw('count(id) as totalservice,max(created_date) as last_service,service_provider_id,id,service_id,account_id,service_request,created_date')->with(['account' => function($first) use ($keyword) {
$first->select('id', 'restaurant_name')->orderBy('restaurant_name', 'DESC');
}])
->with(['serviceProvider' => function($query) use ($keyword) {
$query->select('id', 'company_name');
}])->groupBy('account_id')
->orderBy('company_name', 'DESC')
->paginate(100);
I need an order by on model relation table field and that effect on main table data. because it's and one to one relationship so no need to order by on the inside.
Like I need to the orderby whole on relations data.
Collection:
You must make join your relation table to used orderBy relation table.
You can try this code.
$servicerequest = ServiceRequest::selectRaw('count(id) as totalservice, max(created_date) as last_service,service_provider_id,id,service_id,account_id,service_request,created_date, SERVICEPROVIDERTABLE.company_name')
->join('serviceProvider', 'SERVICEPROVIDERTABLE.id', '=', 'SERVICEREQUESTTABLE.service_provider_id')
->with([
'account' => function ($first) use ($keyword) {
$first->select('id', 'restaurant_name')
->orderBy('restaurant_name', 'DESC');
}
])
//->with([
// 'serviceProvider' => function ($query) use ($keyword) {
// $query->select('id', 'company_name');
// }
//])
->groupBy('account_id')
->orderBy('SERVICEPROVIDERTABLE.company_name', 'DESC')
->paginate(100);
i hope this works.

PHP Laravel (->with) only 1 result

I have 2 models: TheSeries and TheEpisodes.
TheSeries has many TheEpisodes and TheEpisodes has one TheSeries.
I am trying to list all TheSeries and display latestEpisode in each, by using TheEpisodes.addDate.
The code I have right now is this:
$TheSeries = TheSeries::with('TheEpisodes');
What should I do to display only latest 1 episode for each TV serial?
EDIT
->take(1) and ->limit(1) do not work for TheEpisodes
EDIT (Latest Semi-Working Code)
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc');
}])->get()
This works, it returns the episodes in correct order but I am unable to limit the results to 1. This following codes don't work:
// Example 1
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->take(1);
}])->get()
// Example 2
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->limit(1);
}])->get()
// Example 3
$results = TheSeries::take(5)->with(['TheEpisodes' => function($q) {
$q->orderBy('addDate', 'desc')->first();
}])->get()
Those are the column names of the tables:
TheSeries - id, originalTitle, aliasTitle, description, imageURL, startingDate, endingDate, activeBool
TheEpisodes: id, seriesID, authorID, addDate, episodeVersion
Define a TheLatestEpisode hasOne relation on your TheSeries model:
class TheSeries extends Model
{
public function TheLatestEpisode()
{
return $this->hasOne(TheEpisode::class, 'seriesID')->orderBy('id', 'desc');
}
}
Then you can easily do:
$series = TheSeries::with('TheLatestEpisode')->get();
You can try it as:
$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->take(1);
}])
->get();
Or try with limit as:
$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->limit(1);
}])
->get();
$TheSeries = TheSeries::with(['TheEpisodes' => function($q) {
$q->orderBy('created_at', 'desc')->first();
}])
->get();
can't work?
Why don't you use the DB statement ?
DB::table('TheEpisodes')
->leftjoin('TheSeries','TheEpisodes.SeriesId','=','TheSeries.id')
->select('TheEpisodes.*','TheSeries.id as sId','TheSeries.name as sName',...)
->orderBy('TheEpisodes. addDate','desc')
->take(1)
->get();
You can try something like this in your TheSeries model: (it is easier)
public function getLatestEpisodeAttribute(){
$episode = TheEpisodes::where('series_id',$this->attributes['id'])
->latest()
->first();
if(!$episode){
return "no episodes for this Series";
}
return $episode;
}
On your controller just do the query normally without including anything related to TheSeries and you can access it values in your blade file like this:
//lets suppose there is a title attibute in the episodes
{{$TheSeries->latest_episode->title}}
//or a duration attribute
{{$TheSeries->latest_episode->duration}}
The best solution I found, was to create a one-to-one relationship with orderBy('addDate'), it works!!!
Reference: https://softonsofa.com/tweaking-eloquent-relations-how-to-get-latest-related-model/
$TheSeries = TheSeries::with('TheEpisodes')->first();
Or
$TheSeries = TheSeries::with('TheEpisodes')->firstOrFail();

Categories