[php] 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.

This question is related to php mysql sql laravel laravel-4

The answer is


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 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.


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
    });

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();

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


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;

```


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();

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"')
                            ));

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


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();

Warning: untested code.

$dailyData = DB::table('page_views')
    ->select('created_at', DB::raw('count(*) as views'))
    ->groupBy('created_at')
    ->get();

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)'));

PageView::select('id','title', DB::raw('DATE(created_at) as date'))
          ->get()
          ->groupBy('date');

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();

Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to mysql

Implement specialization in ER diagram How to post query parameters with Axios? PHP with MySQL 8.0+ error: The server requested authentication method unknown to the client Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver' phpMyAdmin - Error > Incorrect format parameter? Authentication plugin 'caching_sha2_password' is not supported How to resolve Unable to load authentication plugin 'caching_sha2_password' issue Connection Java-MySql : Public Key Retrieval is not allowed How to grant all privileges to root user in MySQL 8.0 MySQL 8.0 - Client does not support authentication protocol requested by server; consider upgrading MySQL client

Examples related to sql

Passing multiple values for same variable in stored procedure SQL permissions for roles Generic XSLT Search and Replace template Access And/Or exclusions Pyspark: Filter dataframe based on multiple conditions Subtracting 1 day from a timestamp date PYODBC--Data source name not found and no default driver specified select rows in sql with latest date for each ID repeated multiple times ALTER TABLE DROP COLUMN failed because one or more objects access this column Create Local SQL Server database

Examples related to laravel

Parameter binding on left joins with array in Laravel Query Builder Laravel 4 with Sentry 2 add user to a group on Registration Target class controller does not exist - Laravel 8 Visual Studio Code PHP Intelephense Keep Showing Not Necessary Error The POST method is not supported for this route. Supported methods: GET, HEAD. Laravel How to fix 'Unchecked runtime.lastError: The message port closed before a response was received' chrome issue? Post request in Laravel - Error - 419 Sorry, your session/ 419 your page has expired Expected response code 250 but got code "530", with message "530 5.7.1 Authentication required How can I run specific migration in laravel Laravel 5 show ErrorException file_put_contents failed to open stream: No such file or directory

Examples related to laravel-4

Parameter binding on left joins with array in Laravel Query Builder Laravel 4 with Sentry 2 add user to a group on Registration 'Malformed UTF-8 characters, possibly incorrectly encoded' in Laravel Can I do Model->where('id', ARRAY) multiple where conditions? how to fix stream_socket_enable_crypto(): SSL operation failed with code 1 Rollback one specific migration in Laravel How can I resolve "Your requirements could not be resolved to an installable set of packages" error? Define the selected option with the old input in Laravel / Blade Redirect to external URL with return in laravel laravel the requested url was not found on this server