Laravel Postgres Formatted Date Month Year Error Ordering Dates - php

I have a database that looks like this :
I want to make a graph of total costs across a specified period based on different statuses. My query is returning month/year and the total cost at that time.
Despite using order by to display data in an ascending order, my graph is quite unordered. This is how my query looks :
$delivery_failure = DB::table('partners_sms')->select(DB::raw('month, sum(sum) as y'))
->whereBetween('created_at', [new Carbon($start_date), new Carbon($end_date)])
->where('failure_reason', '=', 'DeliveryFailure')
->groupBy('month')
->orderBy('month', 'DESC')
->get();
I have also tried this approach with no luck:
$successNonPartner = SMSData::query()->selectRaw("to_char(created_at::timestamp, 'MONTH-YYYY') as month")
->whereBetween('created_at', [new Carbon($start_date), new Carbon($end_date)])
->where('status', '=', 'Success')
->groupBy('created_at')
->orderBy('created_at', 'DESC')
->get();
Any advise or recommendations on an ideal approach to format my date in month/year and order the dates will be appreciated. I am using laravel and postgres.

to_char(created_at,'YYYY-MONTH') will be of help but it returns a string, probably why order_by doesn't work. You can try returning dates, order by will work and then convert the date to a format of choice in the graph
$successNonPartner = SMSData::selectRaw("month, CEIL(sum(sum)) as y")
->whereBetween('created_at', [new Carbon($start_date), new Carbon($end_date)])
->where('status', '=', 'Success')
->groupBy('month')
->orderBy('month', 'DESC')
->get();

Related

Laravel whereDate not working

I want to load more links of day, but the whereDate not working, and I don't know why... The date format is correct.
public function day_load_more($clicks, $total_links, $data) {
$data_carbon = Carbon::createFromFormat('d-m-Y h:i:s', '20-02-2018 00:00:00');
$ex_link_in = explode(',', $_POST['links_inserts']);
$links = Link::where('status', '=', 1)
->WhereNotIn('id', $ex_link_in)
->whereDate('created_at', $data_carbon)
->where('clicks', '<=', $clicks)
->orderBy('clicks', 'desc')
->with('page', 'tag')
->where('sponsored', 0)
->take(10)
->get();
}
The stranger thing, is that in the other method works fine (show only links of day):
public function linksofday($data){
$data_carbon = Carbon::createFromFormat('d-m-Y h:i:s', '20-02-2018 00:00:00');
$links = Link::where('status', '=', 1)
->orderBy('clicks', 'desc')
->with('page', 'tag')
->where('sponsored', 0)
->whereDate('created_at', $data_carbon)
->whereNotIn('id', [$this->getFirstLinkDay($data)->id])
->take(10)
->get();
}
I got 5 links of day 20-02, when I roll the page, should not show anything more, but shows links of others days...
I don't think the issue is with your parsing of the date but rather with some other where or maybe because some of the input variable has wrong data, also instead of using $_POST you can just access it's data with Request object

How to use now() with Eloquent?

What the best way to use now() with Eloquent? I mean, is there a native Eloquent function to return today's date? I'm using Slim framework and for this query, the only solution that I found is:
$now = date('Y/m/d H:i:s', time());
$articles = Article::where('created_at', '<', $now)
->orderBy('created_at', 'DESC')
->limit(10)
->get();
It's a bit messy, isn't it?
I could use Carbon but it would make an extra dependency...
Thanks
You have two options here: either use DB::raw method to make where method process the given expression as is:
$articles = Article::where(DB::raw('created_at < NOW()'))
->orderBy('created_at', 'DESC')
->limit(10)
->get();
... or use whereRaw method:
$articles = Article::whereRaw('created_at < NOW()')
->orderBy('created_at', 'DESC')
->limit(10)
->get();
As a sidenote, Eloquent has several helper methods for datetime-related processing - whereDate, whereMonth, whereDay, whereYear and whereTime. I'm really not sure those can be used in this specific case, but they might turn helpful elsewhere.

With Eloquent only extract items with a complete date

I just want to extract items that have a complete date, Unfortunately video games do not always have a precise date While others are deleted.
For this reason some of my dates, rather than being composed "2017-03-29" they have: "2017" or "Deleted"
This is my code:
$giochi = InfoGiochi::with('Giochi')
->where('data', '>=', Carbon::now()->subMonth())
->paginate(10);
I try with:
->where('data', date('Y-m-d'))
While:
Carbon::now()->subMonth()
I want to extract only complete dates, that is, composed "Y/m/d".
Because now it also extracts incomplete dates, such as: "2017" or "delete".
Resolved with:
$giochi = InfoGiochi::with('Giochi')
->whereMonth('data', '=', date('m'))
->whereYear('data', date('Y'))
->get();

Laravel Eloquent date range between range

I am building a website where i have a booking mechanism.
The user can book a hotel room for X days if the room is available.
I am using:
Laravel 5.4
MySql
The room is unavailable if:
It is already booked by another user
The admin has set it as unavailable
The room capacity is less or equal to the number of travellers
If have 3 tables to store those data:
Rent: Contains the booking infos, such as rentStartDate and rentEndDate (as DateTime) and other fields (userId, rentalId, ...)
Unavailabilities: When the admin set a room as unavailable, it's stored here. I have the fields unavailabilityStartDate, unavailabilityEndDate (as DateTime) and rentalId
Rentals: This table contain all the infos regarding the room (capacity ,name, location, ...)
I am struggling to build a Eloquent query to check if the room is available before processing the user payment. Here is what i have for now:
public function isAvailableAtDates($rentalId, $startDate, $endDate, $capacity) {
$from = min($startDate, $endDate);
$till = max($startDate, $endDate);
$result = DB::table('rentals')
->where([
['rentals.rentalId', '=', $rentalId],
['rentals.rentalCapacity', '>=', $capacity]
])
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('unavailabilities.rentalId')
->from('unavailabilities')
->where([
['unavailabilities.rentalId', '=', $rentalId],
['unavailabilityStartDate', '>=', $from],
['unavailabilityEndDate', '<=', $till],
]);
})
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('rent.rentalId')
->from('rent')
->where([
['rent.rentalId', '=', $rentalId],
['rentStartDate', '>=', $from],
['rentEndDate', '<=', $till]
]);
})
->select('rentals.rentalId')
->get();
return count($result) == 1;
}
Let's say I have a row inside Unavailabilities with:
unavailabilityStartDate = 2017-04-26 00:00:00
unavailabilityEndDate = 2017-04-30 00:00:00
When calling the method with some dates outside of the range stored in Unavailabilities, i'm getting the expected result. When calling it with the exact same dates, i'm getting no result (which is what i want).
So far so good!
The problem is if i'm calling it with a start date between 26 of April and 30th and a end date later in May, i am still getting a result even tho i shouldn't.
Could anyone help me with that?
This is not a laravel, nor a mysql issue.
try this:
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('unavailabilities.rentalId')
->from('unavailabilities')
->where([
['unavailabilities.rentalId', '=', $rentalId],
['unavailabilityStartDate', '<=', $till],
['unavailabilityEndDate', '>=', $from],
]);
})
->whereNotIn('rentals.rentalId', function($query) use ($from, $till, $rentalId) {
$query->select('rent.rentalId')
->from('rent')
->where([
['rent.rentalId', '=', $rentalId],
['rentStartDate', '<=', $till],
['rentEndDate', '>=', $from]
]);
})
You need all rent and unavailabilities records that had been started before $till and hadn't been ended before $from date.
Try to draw a time diagram.

Laravel Eloquent get results grouped by days

I currently have a table of page_views that records one row for each time a visitor accesses a page, recording the user's ip/id and the id of the page itself. I should add that the created_at column is of type: timestamp, so it includes the hours/minutes/seconds. When I try groupBy queries, it does not group same days together because of the seconds difference.
created_at page_id user_id
========== ======= =======
10-11-2013 3 1
10-12 2013 5 5
10-13 2013 5 2
10-13 2013 3 4
... ... ...
I'd like to get results based on views/day, so I can get something like:
date views
==== =====
10-11-2013 15
10-12 2013 45
... ...
I'm thinking I'll need to dig into DB::raw() queries to achieve this, but any insight would help greatly, thanks
Edit: Added clarification of created_at format.
I believe I have found a solution to this, the key is the DATE() function in mysql, which converts a DateTime into just Date:
DB::table('page_views')
->select(DB::raw('DATE(created_at) as date'), DB::raw('count(*) as views'))
->groupBy('date')
->get();
However, this is not really an Laravel Eloquent solution, since this is a raw query.The following is what I came up with in Eloquent-ish syntax. The first where clause uses carbon dates to compare.
$visitorTraffic = PageView::where('created_at', '>=', \Carbon\Carbon::now->subMonth())
->groupBy('date')
->orderBy('date', 'DESC')
->get(array(
DB::raw('Date(created_at) as date'),
DB::raw('COUNT(*) as "views"')
));
You can use Carbon (integrated in Laravel)
// Carbon
use Carbon\Carbon;
$visitorTraffic = PageView::select('id', 'title', 'created_at')
->get()
->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('Y'); // grouping by years
//return Carbon::parse($date->created_at)->format('m'); // grouping by months
});
Here is how I do it. A short example, but made my query much more manageable
$visitorTraffic = PageView::where('created_at', '>=', \Carbon\Carbon::now->subMonth())
->groupBy(DB::raw('Date(created_at)'))
->orderBy('created_at', 'DESC')->get();
Like most database problems, they should be solved by using the database.
Storing the data you want to group by and using indexes you can achieve an efficient and clear method to solve this problem.
Create the migration
$table->tinyInteger('activity_year')->unsigned()->index();
$table->smallInteger('activity_day_of_year')->unsigned()->index();
Update the Model
<?php
namespace App\Models;
use DB;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
class PageView extends Model
{
public function scopePerDay($query){
$query->groupBy('activity_year');
$query->groupBy('activity_day_of_year');
return $query;
}
public function setUpdatedAt($value)
{
$date = Carbon::now();
$this->activity_year = (int)$date->format('y');
$this->activity_day_of_year = $date->dayOfYear;
return parent::setUpdatedAt($value);
}
Usage
$viewsPerDay = PageView::perDay()->get();
You can filter the results based on formatted date using mysql (See here for Mysql/Mariadb help) and use something like this in laravel-5.4:
Model::selectRaw("COUNT(*) views, DATE_FORMAT(created_at, '%Y %m %e') date")
->groupBy('date')
->get();
I had same problem, I'm currently using Laravel 5.3.
I use DATE_FORMAT()
->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m-%d')"))
Hopefully this will help you.
PageView::select('id','title', DB::raw('DATE(created_at) as date'))
->get()
->groupBy('date');
To group data according to DATE instead of DATETIME, you can use CAST function.
$visitorTraffic = PageView::select('id', 'title', 'created_at')
->get()
->groupBy(DB::raw('CAST(created_at AS DATE)'));
Warning: untested code.
$dailyData = DB::table('page_views')
->select('created_at', DB::raw('count(*) as views'))
->groupBy('created_at')
->get();
I know this is an OLD Question and there are multiple answers. How ever according to the docs and my experience on laravel below is the good "Eloquent way" of handling things
In your model, add a mutator/Getter like this
public function getCreatedAtTimeAttribute()
{
return $this->created_at->toDateString();
}
Another way is to cast the columns
in your model, populate the $cast array
$casts = [
'created_at' => 'string'
]
The catch here is that you won't be able to use the Carbon on this model again since Eloquent will always cast the column into string
Hope it helps :)
Using Laravel 4.2 without Carbon
Here's how I grab the recent ten days and count each row with same day created_at timestamp.
$q = Spins::orderBy('created_at', 'desc')
->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m-%d')"))
->take(10)
->get(array(
DB::raw('Date(created_at) as date'),
DB::raw('COUNT(*) as "views"')
));
foreach ($q as $day) {
echo $day->date. " Views: " . $day->views.'<br>';
}
Hope this helps
You could also solve this problem in following way:
$totalView = View::select(DB::raw('Date(read_at) as date'), DB::raw('count(*) as Views'))
->groupBy(DB::raw('Date(read_at)'))
->orderBy(DB::raw('Date(read_at)'))
->get();
this way work properly and I used it in many projects!
for example I get data of views the last 30 days:
$viewsData = DB::table('page_views')
->where('page_id', $page->id)
->whereDate('created_at', '>=', now()->subDays(30))
->select(DB::raw('DATE(created_at) as data'), DB::raw('count(*) as views'))
->groupBy('date')
->get();
If you want to get the number of views based on different IPs, you can use the DISTINCT like below :
$viewsData = DB::table('page_views')
->where('page_id', $page->id)
->whereDate('created_at', '>=', now()->subDays(30))
->select(DB::raw('DATE(created_at) as data'), DB::raw('count(DISTINCT user_ip) as visitors'))
->groupBy('date')
->get();
You can easily customize it by manipulating the columns name
you can use the following code to group them by the date, since you have to parse both in the selection query and in the groupBy method:
$counts = DB::table('page_views')->select(DB::raw('DATE(created_at) as created_at'), DB::raw('COUNT(*) as views'))->
groupBy(DB::raw('DATE(created_at)'))->
get();
in mysql you can add MONTH keyword having the timestamp as a parameter
in laravel you can do it like this
Payement::groupBy(DB::raw('MONTH(created_at)'))->get();
I built a laravel package for making statistics : https://github.com/Ifnot/statistics
It is based on eloquent, carbon and indicators so it is really easy to use. It may be usefull for extracting date grouped indicators.
$statistics = Statistics::of(MyModel::query());
$statistics->date('validated_at');
$statistics->interval(Interval::$DAILY, Carbon::createFromFormat('Y-m-d', '2016-01-01'), Carbon::now())
$statistics->indicator('total', function($row) {
return $row->counter;
});
$data = $statistics->make();
echo $data['2016-01-01']->total;
```
Get pages views (or whatever), group my year-month-day and count for each date:
PageView::get()
->groupBy(fn($pv) => $pv->created_at->format('Y-m-d'))
->map(fn($date) => count($date));

Categories