Getting specific date ranges from database in Laravel - php

I need to get results from a DB divided by dates such as today, yesterday, this week, last week, etc.
I can easily do this with whereRaw and some SQL:
whereRaw('Date(created_at) = CURDATE()')->get();
I wonder if there is an easier, proper way to do this with Eloquent.

You could create a scope for a particular class like this:
public function scopeYourQuery($query, $user) {
return $query->where('user_id', $user->id)->orderBy('created_at', 'desc')->first();
}
This just gets the first item of a descending ordered list ordered by created_at date per user.
If you wanted something that was between date ranges? You just pass in your date and extend it a bit with some PHP, maybe something like this would work:
public function scopeSomeDateQuery($query, $fetch_date, $user)
{
//clone the users chosen month - so we can make the range until the following month
$also_fetch_date = clone $fetch_date;
$next_month = $also_fetch_date->addMonth();
$next_month = $next_month->format('Y-m-d');
$fetch_date = $fetch_date->format('Y-m-d');
//return the query for the monthname
return $query->orderBy('created_date')->where('created_date', '>=', $fetch_date)->where('created_date', '<', $next_month)->where('user_id', $user->id);
}
This would look in a monthly range (per user) to get an ordered list of items with a created_date in that range.

Related

Laravel Carbon, querying database where a field date is 2 weeks less than itself

I have a Election model, where I'm trying to write a query that will show me specific results.
The idea is pretty simple:
A Election starting_date, for example is 15/10/2018.
I need my query to show all elections that will start in next 2 weeks.
I mean, for that specific case, today is 01/10/2018, so I need all elections that will start in period 01/10/2018 - 15/10/2018.
So, I tried to write something like:
public function notificationBeforeCollection() {
return $this->activeElections()
->where('start_collection', '>=', Carbon::now()
->subDays(14)->format('Y-m-d'))
->where('start_collection', '<', Carbon::now()
->format('Y-m-d'));
}
But it doesn't work, and it looks like it can't work by comparing the starting_date with today. It looks like I need to write something like:
where('starting_date', '>=', 'starting_date'->subDays(14);
If I'm right, is there a way how to use Carbon against a field in query builder?
Your actual query is looking for all elections that started 14 days ago.
You need to do something like:
return $this->activeElections()->where('start_collection', '>', Carbon::today())
->where('start_collection', '<=' Carbon::today()->addDays(14));
To get 'Elections' of two weeks from tomorrow
// using 'Carbon'
$start_date = Carbon::now()->addDay()->format('Y-m-d');
$end_date = Carbon::now()->addDays(14)->format('Y-m-d');
public function notificationBeforeCollection() {
return $this->activeElections()->whereBetween(
'start_collection', [$start_date, $end_date]
);
}

How to get last 12 months user login data by per month in laravel

I am trying to get user login activity per month and then to show it in statistic in a bar chat. But the problem i am facing is that its not giving me any data. I will share my code first it will easier to explain my problem
My LoginActivity Model
class LogActivity extends Model
{
protected $table = 'laravel_logger_activity';
public function logActivity(){
$videoPerMonth = array();
for ($i=1; $i<=12; $i++){
$age= 12 - $i;
$userPerMonth[$i] = count(LogActivity::whereNotIn('userId', [1])->whereMonth('created_at', '=', date('n') -$age)->get());
}
}
}
In this i do get user's activity per month but this is not accurate because being the first month if u subtract 12 value goes to negative. And i dont get actual reults.
So, after reading few articles i changed my code to this
$userPerMonth =count( LogActivity::whereNotIn('userId', [1])->whereMonth('created_at', '>=', Carbon::now()->subMonth(12))->get());
return json_encode($userPerMonth);
But this returns empty.What shall i do ?
I want to get data by month vs activity
For example nov 2017 : 300 , dec 2017:800,jan 01 2018:100
Something like that so i can put in bar chat
Can anyone please help me with this
Thanks
I would be tempted to tackle this in a different way, instead of trying to get the user's login activity per month in a loop. I would get the user's login activity for a date range such as a year. This would result in one SQL query being run rather than 12 per user. Once you have the data you can loop through the results and sort them into an array or collection.
Or you could do it as the equivalent of this SQL statement.
SELECT COUNT(*) as login_num, DATE_FORMAT(created, '%m') as login_month, user_id
FROM login_tokens
WHERE created_at >= '2017-01-01 00:00:01' AND created_at <= '2017-12-31 23:59:59'
GROUP BY user_id, login_month
I think to do this in eloquent you would need to do the following;
$logActivity = LogActivity::where(‘created_at’, ‘>=’, ‘2017-01-01 00:00:01’)
->where(‘created’, ‘<=’, ’23:59:59’)
->select(\DB:raw(‘COUNT(*) as login_num, DATE_FORMAT(created, '%m') as login_month, user_id’))
->groupBy(‘user_id’)
->groupBy(‘login_month’)
->get();
Downside to this approach is you're having to put in knowledge of the SQL language, which could differ from MySql, to SQLite, MSSQL etc.
A useful tip if you remove the get() and replace it with toSql() you can echo out the query.
echo LogActivity::where(‘created_at’, ‘>=’, ‘2017-01-01 00:00:01’)
->where(‘created’, ‘<=’, ’23:59:59’)
->select(\DB:raw(‘COUNT(*) as login_num, DATE_FORMAT(created, '%m') as login_month, user_id’))
->groupBy(‘user_id’)
->groupBy(‘login_month’)
->toSql();
dd();
Hope that helps a bit.
I've knocked together a simple class that is more or less what I think you're after. Please note that the use statements are probably not quite right and I've not run this code, so use it as an example. Basically what I've done here is get the current date and work out the previous year from now.
That is then used to select the data from the database within getActivity method. An empty array is created $dateRange for storing the results in with the keys being the year and the month i.e. 2018-02, 2018-01, 2017-12, 2017-11 and so on.
Next I'm doing a simple check to see if we actually have any results from the database because if there are no results then the logins would be 0 for each month.
Then get a date range, okay I've swapped back to standard PHP date interval here as I don't know the Carbon syntax of the top of my head, but as Carbon extends PHP's DateTime it probably should work. However, it may need some tweaking here as well. So get the date range between the two dates by a monthly interval.
Then loop through this date range, use the $hasLoginActivity variable we defined earlier and if that's false add the date range formatted to year-month as the key and the value to zero.
If we have results then add the date range with the same formatting and get the data from the results. As we have returned a collection from Laravel's ORM we should be able to where on it again, see Collections docs. Store this to a variable and check to see if we have results before trying to access the property, else set to zero. You might be able to skip this and access it like $loginActivity->where('login_year_month', $date->format('Y-m'))->login_num; but I can't remember of the top of my head if this causes an error trying to access property on a null value.
I hope this helps.
<?php
use Carbon;
use DateInterval;
use DatePeriod;
use LogActivity as LogActivityModel;
class LogActivity
{
public function annualActivity(): array
{
// Get the current date/time and get a year from now.
$now = new Carbon();
$aYearAgo = $now->clone()->subYears(1);
// Get any login activity from the last year to now.
$loginActivity = $this->getActivity($aYearAgo, $now);
$dateRange = [];
$hasLoginActvity = $loginActivity->count();
// Get a date range from a year ago to now and loop through them.
foreach ($this->getDateRange($aYearAgo, $now) as $date) {
// If we there were no results, then just create the array with a result set of zero.
if (! $hasLoginActvity) {
$dateRange[$date->format('Y-m')] = 0;
continue;
}
$monthActivity = $loginActivity->where('login_year_month', $date->format('Y-m'));
$loginCount = $monthActivity ? $monthActivity->login-num : 0;
// Add to the array the date YYYY-MM as the key i.e. 2018-02 and search the collection for the same date.
$dateRange[$date->format('Y-m')] = $loginCount;
}
// Return the array date with the year and month as the key and a integer as the value.
return $dateRange;
}
private function getActivity(Carbon $aYearAgo, Carbon $now)
{
return LogActivityModel::where(‘created_at’, ‘>=’, $aYearAgo->format('Y-m-d H:i:s'))
->where(‘created_at’, ‘<=’, $now->format('Y-m-d H:i:s'))
->select(\DB:raw(‘COUNT(*) as login_num, DATE_FORMAT(created, '%Y-%m') as login_year_month, user_id’))
->groupBy(‘user_id’)
->groupBy(‘login_month’)
->all();
}
private function getDateRange($from, $to)
{
// Get a the date range between the two dates with an interval of a month.
return new DatePeriod($from, new DateInterval('P1M') ,$to);
}
}

Laravel Eloquent whereDate() with UnixTimestamps

the entries in my database have a custom timestamp field (e.g. 1488446089).
How do I use whereDate() or whereDay() with unix timstamps?
This of course just works for Date Fields.
$posts = Post::whereDay('uploaded_time', '=', '2017-05-10')->get();
To run it correctly use whereDate instead of whereDay
$posts = Post::whereDate('uploaded_time', '2017-05-10')->get();
To get all specific day means (date of month like 1-30)
$posts = Post::whereDay('uploaded_time', '10')->get();//provide date of month
get more detail : https://laravel.com/docs/master/queries#where-clauses
One way to do this is fetching all Posts, and then filtering the results in PHP:
$myDate = '2017-05-10';
$posts = Post::all()->filter(function (Post $post) use ($myDate) {
$uploadedAt = Carbon::createFromTimestamp($post->uploaded_time)->format('Y-m-d');
return $uploadedAt === $myDate;
});
Why? Because if I'm right you are trying to fetch all posts that were uploaded on a certain date. This means that there is a range of timestamps valid. (60 * 60 * 24). With Carbon (comes with Laravel) you can easily convert your timestamps to Y-m-d formatted strings. Those you then compare to the date string of your choice.
Edit
I have no way to test this at the moment, but it should be possible to do this with a query builder after all:
$myDate = Carbon::createFromFormat('Y-m-d', '2017-05-10');
$startOfDayTimestamp = $myDate->startOfDay()->timestamp;
$endOfDayTimestamp = $myDate->endOfDay()->timestamp;
$posts = Post::whereBetween('uploaded_time', [
$startOfDayTimestamp,
$endOfDayTimestamp
])->get();
Here we create 2 timestamps, one for the very start of the date you wish to filter by, and one for the very end. After that, we can use the builder's whereBetween() method and pass the 2 timestamps.
I found this solution here, and simplified a little bit by replacing the setTime() calls with startOfDay and endOfDay methods.

If to compare two dates using Carbon on Laravel, a date from a table and a now() instance

I'm trying to display some items from a table and I'm ordering by the time they begin, I only want to show the next three items starting from now(). Here is my controller function:
Probably the whole thing is completely wrong, but still, any help will be greatly appreciated.
public function next(Request $request)
{
$eventos = Event::orderBy('start','asc');
$eventTime = Carbon::createFromDate($eventos->start);
$mytime = Carbon::now();
if($eventTime > $mytime){
$eventos = paginate(3);
return view('evento.next',compact('eventos'));
}
}
public function next(Request $request)
{
$eventos=Event::where('start','>=',Carbon::now()) // select all recodrs where start Time more than now date
->orderBy('start','asc') // order all records by asc
->take(3) // take first 3 record
->get(); // now get the result
return view('evento.next',compact('eventos'));
}

Laravel groupBy

I'm trying to redesign my Laravel 4.2 code and like to group a list from results over the last days.
code:
public function getTrending($type = null, $category = null)
{
$posts = $this->posts($type, $category)->with('comments', 'votes', 'category', 'user', 'votes.user')
->leftJoin('votes', 'posts.id', '=', 'votes.post_id')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
->select('posts.*', DB::raw('count(comments.post_id)*7 + count(votes.post_id)*30 + posts.views as popular'))
->groupBy('posts.id')->with('user')->orderBy('popular', 'desc')->whereMonth('posts.created_at', '>=', date('n', strtotime('-1 month')))
->paginate(perPage());
return $posts;
}
I want to group the results as it is (relevance: comments, votes, visit) + grouping the results on a daily base.
Like:
Today (with Date xx.xx.xx)
result 1 (Max Votes, Comment, ...)
result 2
result 3
Yesterday (with Date xx.xx.xx)
result 4 (Max Votes, Comments, ...)
result 5
result 6
Is this possible?
You can use Carbon;
->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
});
No I don't believe you can group your data in a single query like that.
Assuming your code is giving you the dataset you desire, without grouping by date, I would loop over the dates I want and get the data for every day and format it with the date heading etc.

Categories