Laravel Eloquent получает результаты, сгруппированные по дням
В настоящее время у меня есть таблица page_views, которая записывает одну строку для каждого посещения посетителем страницы, записи ip/id пользователя и идентификатора самой страницы. Я должен добавить, что столбец created_at имеет тип: timestamp, поэтому он включает часы/минуты/секунды. Когда я пытаюсь выполнить запросы 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
... ... ...
Я хотел бы получить результаты на основе просмотров/дня, поэтому я могу получить что-то вроде:
date views
==== =====
10-11-2013 15
10-12 2013 45
... ...
Я думаю, что мне нужно будет копаться в запросах DB:: raw(), чтобы достичь этого, но любое понимание поможет значительно, спасибо
Изменить: добавлено уточнение формата created_at.
Ответы
Ответ 1
Я считаю, что нашел решение этого, ключ - это функция DATE() в mysql, которая преобразует DateTime в просто Date:
DB::table('page_views')
->select(DB::raw('DATE(created_at) as date'), DB::raw('count(*) as views'))
->groupBy('date')
->get();
Однако это не действительно решение Laravel Eloquent, так как это сырой запрос. Следующее - это то, что я придумал в синтаксисе Eloquent-ish. Первый, где предложение использует даты углерода для сравнения.
$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"')
));
Ответ 2
Вы можете использовать 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
});
Ответ 3
Вот как я это делаю. Короткий пример, но сделавший мой запрос более управляемым
$visitorTraffic = PageView::where('created_at', '>=', \Carbon\Carbon::now->subMonth())
->groupBy(DB::raw('Date(created_at)'))
->orderBy('created_at', 'DESC')->get();
Ответ 4
У меня была такая же проблема, я в настоящее время использую Laravel 5.3.
Я использую DATE_FORMAT()
->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m-%d')"))
Надеюсь, это поможет вам.
Ответ 5
Вы можете отфильтровать результаты на основе форматированной даты, используя mysql (см. Здесь для справки Mysql/Mariadb) и использовать что-то подобное в laravel-5.4:
Model::selectRaw("COUNT(*) views, DATE_FORMAT(created_at, '%Y %m %e') date")->groupBy('date')->get();
Ответ 6
Как и большинство проблем с базой данных, они должны решаться с помощью базы данных.
Храня данные, которые вы хотите сгруппировать, и используя индексы, вы можете найти эффективный и понятный метод решения этой проблемы.
Создать миграцию
$table->tinyInteger('activity_year')->unsigned()->index();
$table->smallInteger('activity_day_of_year')->unsigned()->index();
Обновить модель
<?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);
}
использование
$viewsPerDay = PageView::perDay()->get();
Ответ 7
Чтобы группировать данные в соответствии с DATE вместо DATETIME, вы можете использовать функцию CAST.
$visitorTraffic = PageView::select('id', 'title', 'created_at')
->get()
->groupBy(DB::raw('CAST(created_at AS DATE)'));
Ответ 8
Предупреждение: непроверенный код.
$dailyData = DB::table('page_views')
->select('created_at', DB::raw('count(*) as views'))
->groupBy('created_at')
->get();
Ответ 9
Использование Laravel 4.2 без Carbon
Вот как я хватаю последние десять дней и подсчитываю каждую строку с тем же днем 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>';
}
Надеюсь, что это поможет
Ответ 10
в mysql вы можете добавить ключевое слово MONTH с меткой времени в качестве параметра
в laravel вы можете сделать это, как это
Payement::groupBy(DB::raw('MONTH(created_at)'))->get();
Ответ 11
Я создал пакет laravel для создания статистики: https://github.com/Ifnot/statistics
Он основан на красноречивых, углеродных и индикаторах, поэтому он очень прост в использовании. Это может быть полезно для извлечения индикаторов сгруппированных по дате.
$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;
`` `
Ответ 12
Я знаю, что это вопрос OLD, и есть несколько ответов. Как бы то ни было согласно документам и моему опыту на laravel ниже, это хороший "Красноречивый способ" обработки вещей.
В вашей модели добавьте мутатор /Getter, как этот
public function getCreatedAtTimeAttribute()
{
return $this->created_at->toDateString();
}
Другим способом является создание столбцов
в вашей модели заполнить массив $cast
$casts = [
'created_at' => 'string'
]
Ловушка здесь заключается в том, что вы не сможете использовать Carbon на этой модели снова, поскольку Eloquent всегда будет отличать колонку в строку
Надеюсь, это поможет:)
Ответ 13
Вы также можете решить эту проблему следующим образом:
$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();
Ответ 14
PageView::select('id','title', DB::raw('DATE(created_at) as date'))
->get()
->groupBy('date');