How to group records in year and month? laravel - laravel

I have been already to this link but its different in my case.
I have record which has a column created_at. My objective is to group the record by year, and inside each year, records should be group in month also.
My expectations:
I have tried this code below, but it is working only for yearly only.
$records = \App\VehicleRental::query()
->where('operator_id', $operator->id)
->get()
->groupBy(function($val) { return \Carbon\Carbon::parse($val->created_at)->format('Y'); });
So I have tried to put another group for month but error Property [created_at] does not exist on this collection instance. returned
$record = \App\VehicleRental::query()
->where('operator_id', $operator->id)
->get()
->groupBy(function($val) { return \Carbon\Carbon::parse($val->created_at)->format('M'); })
->groupBy(function($val) { return \Carbon\Carbon::parse($val->created_at)->format('Y'); });
Someone knows how to achieve this?

You could also pass an array of elements to the groupBy() collection method, for nested grouping. Try this:
$record = \App\VehicleRental::query()
->where('operator_id', $operator->id)
->get()
->groupBy([
function ($val) { return $val->created_at->format('Y'); },
function ($val) { return $val->created_at->format('m'); },
]);
As a side note, the created_at could be directly casted as a Carbon instance. If the above doesn't work, define the attribute date mutator in your model:
# VehicleRental.php
protected $dates = ['created_at', 'updated_at'];

Related

Laravel - Get array with relationship

I have an ajax call that returns an array:
$reports = Report::where('submission_id', $submissionID)
->where('status', 'pending')
->get(['description','rule']);
return [
'message' => 'Success.',
'reports' => $reports,
];
From this array, I only want to return the fields 'description' and 'rule'. However I also want to return the owner() relationship from the Report model. How could I do this? Do I have to load the relationship and do some kind of array push, or is there a more elegant solution?
You can use with() to eager load related model
$reports = Report::with('owner')
->where('submission_id', $submissionID)
->where('status', 'pending')
->get(['id','description','rule']);
Note you need to include id in get() from report model to map (owner) related model
you will have probably one to many relationship with Reports and owners table like below
Report Model
public function owner() {
return $this->belongsTo('App\Owner');
}
Owner Model
public function reports() {
return $this->hasMany('App\Report');
}
your controller code
$reports = Report::with('owner')->
where('submission_id', $submissionID)->where('status', 'pending')->get()
return [
'message' => 'Success.',
'reports' => $reports,
];
This is what I ended up going with:
$reports = Report::
with(['owner' => function($q)
{
$q->select('username', 'id');
}])
->where('submission_id', $submissionID)
->where('status', 'pending')
->select('description', 'rule','created_by')
->get();
The other answers were right, I needed to load in the ID of the user. But I had to use a function for it to work.

GroupBy from relations using laravel eloquent

I have TypeOfVehicle model that has many Vehicle.
How can I group all vehicles by type of vehicle name with counts to get something like this
[
'Sedan' => 10,
'SUV' => 25,
'Crossover' => 5
]
I assume you have eloquent relation type in Vehicle model, e.g.:
public function type()
{
return $this->belongsTo('\App\TypeOfVehicle');
}
So, you can get you data this way:
$result = Vehicle::select('vehicle_type_id', DB::raw('count(vehicle_type_id) as cnt'))
->with('type') // with your type relation
->groupBy('vehicle_type_id') // group by type of vehicle
->get() // get collection from database
->pluck('cnt', 'type.name') // get only needful data
->toArray(); // cast to array if necessary
You can use
$counts = DB::table('tablename')
->select('TypeOfVehicle', DB::raw('count(*) as total'))
->groupBy('TypeOfVehicle')
->get();
Counting Related Models
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
$typeOfVehicles = App\TypeOfVehicle::withCount('vehicles')->get();
foreach ($typeOfVehicles as $typeOfVehicle) {
echo $typeOfVehicle->vehicles_count;
}
Try this it gives you your solution
$vehicle=Vehicle::all();
$grouped = $vehicle->groupBy(function ($item, $key) {
return substr($item['that_coloumn_name_like_type'], 0);
});
$groupCount = $grouped->map(function ($item, $key) {
return collect($item)->count();
});
//dd($groupCount); to check it work correctly

How to get datas by month? Laravel Eloquent

Using the created_at column, I want to retrieve data(s) in one query:
from past year
group by month
Expected returned values should:
$data: [
1 : [
//datas for january
],
2 : [
//datas for february
],
//etc.
]
I tried this query:
$data = User::query()
->whereYear('created_at', now()->year - 1)
->get(function ($q){
return groupBy(function ($q){
return Carbon::parse($q->created_at)->format('m');
});
});
But I receive this error:
stripos() expects parameter 1 to be string, object given
Can someone could help me the proper querying for this?
The nested closure functions with same variable names are very confusing, you can simplify things here
Call the groupBy method on the collection after get instead of the builder which only accepts a column name apparently
$data = User::query()
->whereYear('created_at', now()->year - 1)
->get()
->groupBy(function ($q) {
return Carbon::parse($q->created_at)->format('m');
});
See Docs
you should use sql method MONTH() to extract month from date then use groubby .like this :
User::query()->select('created_at', DB::raw('MONTH(created_at) month'))
->whereYear('created_at', now()->subYear())
->groupby('month')
->get();

Laravel: How to get data from 3 tables with relationship

I have 3 Tables:
Customers
id
name
Sales
customer_id
sale_date
Contacts
customer_id
contact_date
There aren't any update operations in the contacts table. Each process opens a new record in the contacts table. So, a user can have more than one records in the contacts table.
Here are my relations in models:
Customer
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function sales()
{
return $this->hasMany(Sale::class);
}
Contact
public function customer()
{
return $this->belongsTo('App\Customer', 'customer_id');
}
Sale
public function customer()
{
return $this->belongsTo('App\Customer');
}
I would like to have the latest record of the contacts table and make it join with the other related tables.
Here is the query which I have tried:
$record = Contact::groupBy('customer_id')
->select(DB::raw('max(id)'));
$result = Customer::query();
$result->where('is_active', 'YES');
$result->with('sales');
$result->whereHas('contacts', function ($q) use($record){
return $q->whereIn('id', $record)->where('result', 'UNCALLED');
});
return $result->get();
In the blade file, I get some result in foreach loops. However, I am unable to get the related data from the sales and contacts table.
#foreach($result as $item)
#foreach($item->sales as $sale) // Has no output and gives error: Invalid argument supplied for foreach()
#foreach($item->contacts as $contact) // Has no output and gives error: Invalid argument supplied for foreach()
Can anyone help me how to display the sale and contact date? Or any idea for how to improve this code quality?
If you want the latest record of the contacts you can declare another relationship on the Customer model, e.g.:
public function latest_contact()
{
return $this->hasOne(Contact::class)->latest('contact_date');
}
BTW you can always declare one or more hasOne additional relationship if you have a hasMany in place the foreign key used is the same.
In this way you can retrieve latest_contact eager loaded with your Customer model:
$customer = Customer::with('latest_contact')->find($id);
Or use this relationship in your queries, something like that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->whereHas('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
Or that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->with('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
If you want you can declare last_contact with the additional where:
public function latest_contact()
{
return $this->hasOne(Contact::class)
->where('result', 'UNCALLED')
->latest('contact_date');
}
This way all other queries should be easier.
I hope this can help you.
I'm not sure, but can you try to do the following:
return Customer::where('is_active', 'YES')
->with([
'sale',
'contact' => function ($query) use($record) {
return $query->whereIn('id', $record)->where('result', 'UNCALLED');
}
])->get();

Sum of Items field in collection of collections

I'm trying to see if it's possible, but I would like to get the sum of a field in an item in a collection of collections.
I have the following in my controller:
$prefiltered_contacts = Contact::with(['donations' => function ($query) use ($request) {
$query->whereMonth('date_received', $request->month)
->whereYear('date_received', $request->year);
}])->get();
$contacts = $prefiltered_contacts ->filter(function ($contact) {
return $contact->donations->isNotEmpty();
});
My donation class has the following:
public function monetary_donations(){
return $this->hasMany('App\Payments_Distribution', 'donation_id','id');
}
Now the last part of this is that in the Payments_Distribution class, there is a field titled amount.
If I was coming directly from the Donation model, I would access the sum of the monetary donations as $donation->monetary_donations->sum('amount'); and I would receive the sum. But how would I go about doing this from the Contact model? Or is that even possible given that it would need to go through a collection of donations to get to the collection of monetary_donations? I'm trying to get a report of all Contacts donations (and monetary donations) and output a subtotal of the monetary_donations for that specific period.
Sum accepts a closure as the argument. So you could do something like this:
$sum = $donations->sum(function ($donation) {
return $donation->monetary_donations->sum('amount');
});
Or 1 level higher (from $contacts):
$sum = $contacts->sum(function ($contact) {
return $contact->donations->sum(function ($donation) {
return $donation->monetary_donations->sum('amount');
});
});
Edit:
I would also recommend eager loading your relationships and filtering out contacts without donations with SQL rather than collections:
$contacts = Contact::with(['donations' => function ($query) use ($request) {
$query
->with('monetary_donations')
->whereMonth('date_received', $request->month)
->whereYear('date_received', $request->year);
}])
->whereHas('donations') // Filter out those without donations with SQL
->get();

Resources