I have a query that is pulling my data from the table based on the created_at column. I am trying to fill in the missing months for the year. So for example, I have data for February, but thats it. How Do i fill in an amount of 0 for January then March-December?
My query to pull out based on the full month name is as follows
$servers = Stat::where('type','servers')->orderBy('created_at', 'asc')->whereYear('created_at', '=', date("Y"))
->select(DB::raw("SUM(amount) as total"))
->get()
->groupBy(function($val) {
return Carbon::parse($val->created_at)->format('F');
});
In this case, I get my February and the total amount. I'd like the rest of the amounts that don't exist to be 0, or fill in the correct info if it exists later in the year.
You are using sum() for the whole year, and using groupBy method on collection, so there is only one month.
You need to group by month like this:
$servers = Stat::where('type','servers')
->orderBy('created_at', 'asc')
->whereYear('created_at', '=', date("Y"))
->groupBy(DB::raw("MONTH(created_at)"))
->selectRaw("SUM(amount) as total, create_at")
->get()
->groupBy(function($val) {
return $val->created_at->format('F');
});
and you can use CarbonPeriod to create an initial month array, and then merge to the servers:
$all_month = array();
$period = \Carbon\CarbonPeriod::create('2020-01-01', '1 month', '2021-12-31');
foreach ($period as $p) {
$m = $p->format('F');
if (isset($servers[$m])) {
$all_month []= [$m => $servers[$m]->first()->total];
} else {
$all_month []= [$m => 0];
}
}
Related
I've got a query in my Laravel project that returns a collection of data from my database between two dates, it's then grouped by the hour (but I can change this to my liking), I'd now like to return the "dates" for data before they existed in the database as a way of building up a list of dates that I can display in my web page, eve though there will be no data for these days, my chart would look consistent.
As an example:
I want to see the past 30 days of data as a history, but the first 20 days of this period have no data yet, I still need to return the date keys for these days, except with just no data in them.
My current code is as follows (I'm using Carbon):
$uptimeData = UptimeChecks::where('user_id', 1)
->where('monitor_id', 1)
->where('checked_at', '>=', '2021-01-01 00:00:00')
->where('checked_at', '<=', '2021-01-30 23:59:59')
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$from = Carbon::now()->subDays(60);
$period = CarbonPeriod::create($from, '2021-01-30 23:59:59');
$dates = $period->toArray();
foreach ($dates as $key => $date) {
$dates[$key] = Carbon::parse($date)->format('Y-m-d');
}
$uptimeData = collect($uptimeData);
$uptimeData = $uptimeData->merge($dates);
$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) {
if (isset($item->checked_at)) {
$date = Carbon::parse($item->checked_at);
} else {
$date = Carbon::parse($item);
}
return $date->format('Y-m-d');
});
Even though there would be no entries to display a "checked_at" column, can this be spoofed with the date for that day with no data?
Update 03/05 # 20:30
I've updated my description to reflect the latest attempt to solve this problem, I appear to have constructed what I need, however, have some issues:
Where I'm looping over my $dates is there a way to build up some structure within each item so I don't have to do if/else checks on all my variables and keys?
For some reason, the "fake" dummy dates are being added after the real data, e.g: 1st Jan, 2nd Jan, 30th Dec ... how can I reverse this?
One way to achieve this is by creating a collection of the dates for the time period you want, and then merging the results of a query grouped by date into it.
Here's an example:
$from = '2021-01-01';
$to = '2021-01-31';
$period = CarbonPeriod::create($from, $to);
$dates = collect($period->toArray())->mapWithKeys(function ($date) {
return [$date->format('Y-m-d') => []];
});
// $dates = ['2021-01-01' => [], '2021-01-02' => [], ...etc]
$uptimeChecks = UptimeChecks::query()
->where('user_id', 1)
->where('monitor_id', 1)
->whereBetween('checked_at', [$from, $to])
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$uptimeDates = $uptimeChecks->groupBy(function ($item, $key) {
return $item->checked_at->format('Y-m-d');
});
// $uptimeDates = ['2021-01-02' => ['event1', 'event2'], ...etc]
$uptimeData = $dates->merge($uptimeDates);
// $uptimeData = ['2021-01-01' => [], '2021-01-02' => ['event1', 'event2'], ...etc]
This assumes you are casting the checked_at field to a date in your UptimeChecks Model.
I am new to Laravel and not really sure how to do this.
I record dates in my database as start_day in my times table.
Date is persisted with the following format: 2019-10-03
Right now all I have is:
$months = DB::table('times')->where('start_day', '=', 2019)
How should I select data for each month of the year?
use whereYear
use Carbon\Carbon;
$months = DB::table('times')->whereYear('start_day', (string) Carbon::now()->year)->get();
If you want to select months only then
$months = DB::table('times')->select(DB::raw('MONTH(start_day) month')->whereYear('start_day', (string) Carbon::now()->year)->get();
You need to change the where() to whereYear() to search by year.
$months = DB::table('times')->whereYear('start_day', '=', 2019)
write
$month = array():
for($i=1;$i<=12;$i++){
$month[] = DB::table('times')->whereYear('start_day','2019')->whereMonth('start_day',$i)->get();
}
OR
$month = array():
for($i=1;$i<=12;$i++){
$month[] = DB::table('times')->where([['YEAR(start_day)', '=', 2019],['MONTH(start_day)','=',(int)$i]])->get();
}
you can try monthly , weekly , yearly in this format
$weeklyNumberOfSales = Sale::whereBetween('order_date', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])
->sum('qty');
$monthlyNumberOfSales = Sale::whereMonth('order_date',Carbon::now()->format('m'))
->sum('qty');
$yearlyNumberOfSales = Sale::whereYear('order_date',Carbon::now()->format('Y'))
->sum('qty');
model name Sale .
'order_date' and 'qty' are the field name
I want to display in the admin panel statitics about users and other things in the database.
For example to show how many users were registered today, this month etc.
For now I am doing this with the users for today the following way:
$users = User::where('admin', 0)->get();
$usersRegisteredToday = array_filter($users->toArray(), function ($user) {
$registerDate = \DateTime::createFromFormat('Y-m-d H:i:s', $user['created_at']);
$registerDate->setTime(0,0,0);
$today = new \DateTime();
$today->setTime(0,0,0);
$diff = $today->diff($registerDate);
$diffDays = (integer)$diff->format("%R%a"); // Extract days count in interval
return $diffDays == 0;
});
return view('admin.index', compact("users", "usersRegisteredToday"));
And in the view:
<p class="text-no">Today: {{ count($usersRegisteredToday) }} </p>
I wonder if there is a better, simpler and faster way to do this, because I think if I get the information for the other things that way it will be very slow and heavy. So i want to know the best and lightest way to do this.
As of Laravel 5.3 we can use whereDate / whereMonth / whereDay / whereYear
For example to get records created today:
$users = User::whereDate('created_at', DB::raw('CURDATE()'))->get();
Possibly a similar question is asked here: Get only records created today in laravel
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->where('created_at', '>=', $todayStart)
->where('created_at', '<=', $todayEnd)
->get();
You could use query scopes which would make it even better. Inside User model:
class User extends Model
{
public function scopeCreatedBefore(Carbon $date)
{
return $this->where('created_at', '<=', $date);
}
public function scopeCreatedAfter(Carbon $date)
{
return $this->where('created_at', '>=', $date);
}
}
And for the usage:
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->createdAfter($todayStart)
->createdBefore($todayEnd)
->get();
Its quite easy to do it. Im doing this in laravel 5.6
We are working in controller here. Lets say $date1 and $date2 is your range.
First, parse the date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
Now, we get the users within that date range.
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->get(); // or count if you just want to count
basically, the function will look like below
public function betweendates(Request $request)
{
// get dates from request
$date1= $request->olddate;
$date2= $request->newdate;
// parse date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
// the magic stuff
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->count();
return view('users.dashboard', compact('users'));
}
I am attempting to return a count of my users anniversaries by month on a rolling basis, which I will display in flot charts.
I think I nearly have it figured out, but I am struggling with getting the format of my column to match the comparison month.
//return an array of the last 12 months.
for ($i = 1; $i <= 12; $i++) {
$months[] = date("Y-m", strtotime( date( 'Y-m-01' )." -$i months"));
}
//$months dumps as: array(12) { [0]=> string(7) "2015-03" ...}
// find members where the anniversary column matches the $months[$i]
foreach ($months as $key => $value) {
$renewals[] = User::where('anniversary', '=', $value)->count();
}
The format of the anniversary column is 2014-4-30. How to I just grab the 'Y-m' of that column to compare to $month?
You could do:
$renewals[] = User::where('anniversary', 'LIKE', $value.'%')->count();
That would accept any day and only match month and year. Of course there probably are better ways to accomplish this without using LIKE.
Alternatively you could get an array with months that has first and last day and use Laravels whereBetween method.
$renewals[] = User::whereBetween('anniversary', array($firstDay, $lastDay))->count();
Please need help...
$months = Records::select('payment_month')
->distinct()->where('payment_year',$year)
->where('company_id',$company_id)->get();
foreach ($months as $month) {
$data = Records::select(
DB::raw('SUM(record_db.credits) as credits'),
DB::raw('SUM(record_db.amount) as amount'),
DB::raw('SUM(record_db.totalamount) as totalamt'), 'record_db.payment_month')
->where('record_db.company_id','=',$company_id)
->where('record_db.payment_month','=',$month->payment_month)
->where('record_db.payment_year','=',$year)
->first();
}
return Response::json($data);
The above query works fine and I have the month of January, February and March in the database table but it only returns the records of March.
I tried results[]=$data but still don't work.
I think this is what you need:
$data = Records::select(
'payment_month',
DB::raw('SUM(record_db.credits) as credits'),
DB::raw('SUM(record_db.amount) as amount'),
DB::raw('SUM(record_db.totalamount) as totalamt')
)->where('company_id', '=', $company_id)
->where('payment_year', '=', $year)
->groupBy('payment_month')
->orderBy('payment_month')
->get();
// then
$data->toJson(); // returns something like:
[{"payment_month":"January","credits":"123","amount":"456","totalamt":"789"}, ... ]
You had override $data array from every month result. You should use whereIn as follows.
$months = Records::select('payment_month')
->distinct()->where('payment_year', $year)
->where('company_id',$company_id)->get();
$monthValues = array();
foreach ($months as $month) {
$monthValues[] = $month->payment_month;
}
$data = Records::select(
DB::raw('SUM(record_db.credits) as credits'),
DB::raw('SUM(record_db.amount) as amount'),
DB::raw('SUM(record_db.totalamount) as totalamt'), 'record_db.payment_month')
->where('record_db.company_id','=',$company_id)
->whereIn('record_db.payment_month', $monthValues)
->where('record_db.payment_year','=',$year)
->first();