简体   繁体   English

Laravel Eloquent 获取按天分组的结果

[英]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.我目前有一个page_views表,每次访问者访问页面时记录一行,记录用户的 ip/id 和页面本身的 id。 I should add that the created_at column is of type: timestamp , so it includes the hours/minutes/seconds.我应该补充一点, created_at列的类型是: timestamp ,所以它包括小时/分钟/秒。 When I try groupBy queries, it does not group same days together because of the seconds difference.当我尝试groupBy查询时,由于秒数差异,它不会将同一天组合在一起。

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我想我需要深入研究DB::raw()查询来实现这一点,但任何见解都会有很大帮助,谢谢

Edit: Added clarification of created_at format.编辑:添加了对created_at格式的说明。

I believe I have found a solution to this, the key is the DATE() function in mysql, which converts a DateTime into just Date:我相信我已经找到了解决方案,关键是 mysql 中的 DATE() 函数,它将 DateTime 转换为 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.然而,这并不是真正的 Laravel Eloquent 解决方案,因为这是一个原始查询。以下是我在 Eloquent-ish 语法中提出的。 The first where clause uses carbon dates to compare.第一个 where 子句使用碳日期进行比较。

$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(集成在 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();

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:您可以使用 mysql 根据格式化日期过滤结果(请参阅此处获取 Mysql/Mariadb 帮助)并在 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.我有同样的问题,我目前使用的是 Laravel 5.3。

I use DATE_FORMAT()我使用DATE_FORMAT()

->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m-%d')"))

Hopefully this will help you.希望这会帮助你。

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();
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.要根据 DATE 而不是 DATETIME 对数据进行分组,您可以使用 CAST 函数。

$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如何根据文档和我在下面的 laravel 上的经验是处理事情的好“雄辩方式”

In your model, add a mutator/Getter like this在你的模型中,像这样添加一个 mutator/Getter

public function getCreatedAtTimeAttribute()
{
   return $this->created_at->toDateString();
}

Another way is to cast the columns in your model, populate the $cast array另一种方法是在模型中投射列,填充$cast数组

$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这里的问题是您将无法再次在此模型上使用 Carbon,因为 Eloquent 总是将列转换为字符串

Hope it helps :)希望它有帮助:)

Using Laravel 4.2 without Carbon在没有碳的情况下使用 Laravel 4.2

Here's how I grab the recent ten days and count each row with same day created_at timestamp.这是我获取最近十天并使用同一天 created_at 时间戳计算每一行的方法。

$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 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:您可以使用以下代码按日期对它们进行分组,因为您必须在选择查询和 groupBy 方法中进行解析:

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

在mysql中,您可以在laravel中添加具有时间戳的MONTH关键字作为参数,您可以这样做

Payement::groupBy(DB::raw('MONTH(created_at)'))->get();

I built a laravel package for making statistics : https://github.com/Ifnot/statistics我构建了一个用于进行统计的 laravel 包: https : //github.com/Ifnot/statistics

It is based on eloquent, carbon and indicators so it is really easy to use.它基于 eloquent、碳和指标,因此非常易于使用。 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;

``` ``

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:例如,我获取过去 30 天的视图数据:

$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 :如果您想获取基于不同 IP 的视图数量,您可以使用DISTINCT如下所示:

$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您可以通过操作列名称轻松自定义它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM