How to customize Laravel WhereBetween if the value is not found - laravel

Im using Laravel WhereBetween like this
$from = '2015-01-02';
$to = '2015-01-30';
$users = User::whereBetween('created_at', [$from,$to])->get();
If the date value not found in User model, then the date will not show right?
I still want to show the date, even the date not found then I set value to 0.
Then the output will be like this
[
{'2015-01-02': 201},
{'2015-01-03': 0},
{'2015-01-04': 0},
{'2015-01-05': 7},
...
{'2015-01-30': 0}
]
Thanks.

You need to execute following query at first to get all user created at the given range,
$data = User::select([
DB::raw('DATE(created_at) AS date'),
DB::raw('COUNT(id) AS count'),
])
->whereBetween('created_at', [$from,$to])
->groupBy('date')
->orderBy('date', 'ASC')
->get();
With above query, you will get count of user for each day and this will not give 0 value if no users created at that day.
Now, what you have to do is to change above collection to array and insert 0 values if no users created.
$userCount = $data->toArray();
$dataByDay = array();
foreach($userCount as $count){
$dataByDay[$count->date] = $count->count;
}
Now, insert zero values as:
$dateFrom = Carbon::parse($from)->format('Y-m-d');
$dateTo = Carbon::parse($to)->format('Y-m-d');
$days = $dateTo->diffInDays($dateFrom);
for($i=0; $i<$days; $i++){
$dateString = $dateFrom->format('Y-m-d');
if(!isset($chartDataByDay[ $dateString ] {
$dataByDay[ $dateString ] = 0;
}
}
Now, $dataByDay array gives what you want.
Hope you understand.

Related

How to get last 7 days records with 0 counts

I have an eloquent query that gets the total count records (created_at) of the last 7 days. But the problem is if one of these days have 0 records, this doesn't appear in the final data.
My query:
$data = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE(created_at) as date'),
DB::raw('count(*) as total')
])
->pluck('total', 'date')->toArray();
What I get:
[
"2020-04-14" => 1
"2020-04-16" => 1
"2020-04-18" => 1
"2020-04-19" => 1
]
What I expected:
[
"2020-04-14" => 1
"2020-04-15" => 0
"2020-04-16" => 1
"2020-04-17" => 0
"2020-04-18" => 1
"2020-04-19" => 1
"2020-04-20" => 0
]
Any suggestions?
SOLUTION:
-Based on Gary Houbre's proposal:
$results = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d") as date'),
DB::raw('count(*) as total')
])
->keyBy('date')
->map(function ($item) {
$item->date = Carbon::parse($item->date);
return $item;
});
$period = new DatePeriod(Carbon::now()->subDays(6), CarbonInterval::day(), Carbon::now()->addDay());
$graph = array_map(function ($datePeriod) use ($results) {
$date = $datePeriod->format('Y-m-d');
return $results->has($date) ? $results->get($date)->total : 0;
}, iterator_to_array($period));
Looking directly Sql : How to include "zero" / "0" results in COUNT aggregate?
Into a same table : How to get the record if Count is zero in Laravel
You need to add an outer join into your request with Eloquent.
My idea is to create a for loop to check the days.
If there is no record on a date then print 0
Loop Iteration:
Catch the first Day (Suppose 14)
Catch the last Day
Then check in every iteration it is greater than one or many
Thus, I hope you will get normally.
We had a similar problem while trying to put back-end data into the chart. Since some of the days were missing it didn't look well. Our solution was;
Create a function like this;
public function generateDates(Date $startDate, Date $endDate, $format = 'Y/m/d'): Collection
{
$dates = collect();
$startDate = $startDate->copy();
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
$dates->put($date->format($format), 0);
}
return $dates;
}
In your case it's going to be (today and today - six days) and you will union returning collection with your query collection. What it does is; it create a date range from the keys and fill them with zero. When your query collection has some value other than zero - it is going to overwrite it.

how to increment day by one to find the next desired day in laravel

I've an array of day name like ['Wednesday','Sunday','Monday']
now I want to find the next available dates That matched with the array from today's date. I want date. I tried for so long but none of them were successful. My code is given below
$datesAvailable = array();
$count = 0;
$dateToday = Carbon::now()->toDateTimeString();
//$avlDays is the array of day names
$avlDays = DB::table('doctor_schedules')
->select('available_days')
->where('department',$receivedDepartment)
->Where('doctor_id', $receivedDoctor)
->get();
for($k=5; $k > 0; $k++)
{
$dateToday = $dateToday->endOfWeek();
// $parsedDate = Carbon::parse($dateToday);
$dateTodayFormated = new Carbon($dateToday);
$nextDayName = $dateTodayFormated->englishDayOfWeek;
for($i = 0; $i <= 2; $i++)
{
if($avlDays === $nextDayName)
{
$datesAvailable[$count] = $nextDayName;
$count++;
}
}
}
return (['availableDates' => $dateToday]);
Solved
For the current date use
now()
https://laravel.com/docs/6.x/helpers#method-now
Carbon does this.
foreach ($avlDays as $day) {
$nextDay = Carbon::parse("next $day");
// do something with $nextDay...
}
So, assuming $avlDays is returning you a Carbon date range:
$avlDays = DB::table('doctor_schedules')
->select('available_days')
->where('department',$receivedDepartment)
->Where('doctor_id', $receivedDoctor)
->get()
->toArray();
The code below assumes that the array value from ['monday', 'tuesday' ...] is saved as $weekday.
If you are trying to find a specific date within a range that falls on a certain weekday, you can do something like:
$availableAppointments = [];
foreach ($avlDays as $day) {
if ($day->isDayOfWeek($weekday)) {
$availableAppointments[] = $day;
}
Then you can use $availableAppointments to list out the available dates on that day of the week.

access data from database to compare with current date to calculate total days

I have tried to access date stored in my db table and compare it with current date so that I can get the number of days but it shows this error
DateTime::__construct(): Failed to parse time string ([{"quit_date":null},{"quit_date":null}]) at position 0 ([): Unexpected character
This is the code that use in my controller
$quit_date = Information::select('quit_date')
->where('user_id','=',\Auth::user()->id)
->get();
$date = new Carbon($quit_date);
$now = Carbon::now();
$day = $date->diffInDays($now);
but if I set the $quit_date manually with the date for example "2019-04-25 00:00:00.000000", the code works fine and shows the days different between the dates, but when I use the Information::select to read the date from database, it shows error.
use Auth; //top of controller
$checkdate = Information::
->where('user_id','=',Auth::user()->id)
->first();
$quit_date=$checkdate->quit_date;
$date = new Carbon($quit_date);
$now = Carbon::now();
$day = $date->diffInDays($now);
The issue occurs because you are using ->get() at the end of your query. That method returns a Collection not a single object. The issue is solved by using ->first() to return a single object.
The error itself is because in the line $date = new Carbon($quit_date);, Carbon cannot convert a Collection to a date.
This should work:
$quit_date = Information::select('quit_date')
->where('user_id','=', \Auth::user()->id)
->first(); //Changed this from ->get()
$date = new Carbon($quit_date);
$now = Carbon::now();
$day = $date->diffInDays($now);

Laravel : Search by min and max value from the table

I am confuse about search with min-max value.In my posts table there is a two field min_price and max_price, on my search there is a couple of thing which I need to covered in search query.
If user search with only max_value, it shows all the posts which price is less than or equal to max_value.
If user search with only min_value, it shows all the posts which price is less than or equal to min_value.
If user search with min_value and max_value, it shows all the posts which price is between min_value and max_value.
If both null, return all posts.
How can I do this ?
My code:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply);
// skip my search query code
$searchedPost = $searchablePost->offset($offset)->limit($limit)->orderBy('id','desc')->get();
How can I do t
Check:
1. if both (min & max values) are available (i.e. not null):
2. if min value is available:
3. if max value is available:
// if none of them is null
if (! (is_null($min_value) && is_null($max_value))) {
// fetch all between min & max values
$searchablePost = $searchablePost->whereBetween('price', [$min_value, $max_value]);
}
// if just min_value is available (is not null)
elseif (! is_null($min_value)) {
// fetch all greater than or equal to min_value
$searchablePost = $searchablePost->where('price', '>=', $min_value);
}
// if just max_value is available (is not null)
elseif (! is_null($max_value)) {
// fetch all lesser than or equal to max_value
$searchablePost = $searchablePost->where('price', '<=', $max_value);
}
If you have separate fields for min_price & max_price, as mentioned in comment, just change the code as following:
if (! (is_null($min_value) && is_null($max_value))) {
$searchablePost = $searchablePost
->where('min_price', '>=', $min_value)
->where('max_price', '<=', $max_value);
}
elseif (! is_null($min_value)) {
$searchablePost = $searchablePost->where('min_price', '>=', $min_value);
}
elseif (! is_null($max_value)) {
$searchablePost = $searchablePost->where('max_price', '<=', $max_value);
}
You can set $min = 0; and $max = infinite_choosen_number; and append whereBetween method to your query, like the below code:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply)
->whereBetween('price', ["$min", "$max"])->get();
Reference: https://laravel.com/docs/5.6/queries
You can't do that with a whereIn, you can do that with a where statement.
Something like this
`
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply)
->where('price', '>=', $minPrice)
`
Didn't try it so int might fail but here is the way to do it.

Laravel carbon retrieve record even when it shouldn't

I am searching by start and end date or with a weekday, which kind of works fine however if weekday is equal to 'WE' and today's weekday is equal to 'WE' it still brings back results even when $today date is < than endate.
public function show($id)
{
$weekMap = [
0 => 'SU',
1 => 'MO',
2 => 'TU',
3 => 'WE',
4 => 'TH',
5 => 'FR',
6 => 'SA',
];
$todayWeek = Carbon::now()->dayOfWeek;
$today= Carbon::now();
$weekday = $weekMap[$todayWeek];
$event = Event::with('businesses')
->where('startdate', '<', $today->format('Y-m-d'))
->where('endate', '>', $today->format('Y-m-d'))
->orWhere('weekday', '=', $weekday)
->get();
dd($event);
return view('events.showEvent', compact('event'));
}
If I change orWhere to where, results are all good, however user not always enters a weekday so it can be empty. I want it to work like this:
output everything where startdate < today and where endate > today and if weekday is not empty, output everything where startdate < today, endate > today and weekday = $weekday. I hope that makes sense.
//edit
sample data:
data
So what I want is really search by frequency so it would look like this:
if frequency = daily
compare start and end with today's date.
if frequency = weekly
compare start and end with today's date and weekday.
bring back all results for frequency = daily+weekly
you can use if condition in query like this:
$query = Event::with('businesses')
->where('startdate', '<', $today->format('Y-m-d'))
->where('endate', '>', $today->format('Y-m-d'));
if ($weekday != '') {
$query->where('weekday', $weekday);
}
$event = $query->get();
also
condition if ($weekday != '') check $weekday isset or not you can use
if ( ! is_null($weekday )) instead

Resources