web-dev-qa-db-fra.com

Laravel Eloquent obtenir les résultats groupés par jours

J'ai actuellement une table de page_views qui enregistre une ligne chaque fois qu'un visiteur accède à une page, enregistrant l'adresse IP/id de l'utilisateur et l'identifiant de la page elle-même. Je devrais ajouter que la colonne created_at est de type: timestamp, elle inclut donc les heures/minutes/secondes. Lorsque j'essaie des requêtes groupBy, il ne regroupe pas les mêmes jours en raison de la différence en secondes.

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

J'aimerais obtenir des résultats basés sur les vues/jour, afin d'obtenir quelque chose comme:

  date          views
  ====          =====
10-11-2013       15
10-12 2013       45
  ...            ...

Je pense avoir besoin de creuser dans les requêtes DB :: raw () pour y parvenir, mais tout aperçu aiderait grandement, merci

Edit: Ajout de la clarification du format created_at.

30
jct

Je pense avoir trouvé une solution à cela, la clé est la fonction DATE () dans mysql, qui convertit un DateTime en just Date:

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

Cependant, ce n’est pas vraiment une solution Laravel Eloquent, car il s’agit d’une requête brute. Voici ce que j’ai trouvé dans la syntaxe Eloquent. La première où la clause utilise des dates au carbone pour comparer.

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

Vous pouvez utiliser Carbon (intégré à 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
    });
39
dede

Voici comment je le fais. Un petit exemple, mais a rendu ma requête beaucoup plus facile à gérer

$visitorTraffic = PageView::where('created_at', '>=', \Carbon\Carbon::now->subMonth())
                        ->groupBy(DB::raw('Date(created_at)'))
                        ->orderBy('created_at', 'DESC')->get();
18
Quins

Comme la plupart des problèmes de base de données, ils doivent être résolus en utilisant la base de données.

En stockant les données que vous souhaitez regrouper et en utilisant des index, vous pouvez obtenir une méthode efficace et claire pour résoudre ce problème.

Créer la migration

    $table->tinyInteger('activity_year')->unsigned()->index();
    $table->smallInteger('activity_day_of_year')->unsigned()->index();

Mettre à jour le modèle

<?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();
3
henryallsuch

J'ai eu le même problème, j'utilise actuellement Laravel 5.3.

J'utilise DATE_FORMAT()

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

J'espère que cela vous aidera.

3
Haidren Amalia

Vous pouvez filtrer les résultats en fonction de la date formatée en utilisant mysql ( Voir ici pour l'aide de Mysql/Mariadb ) et utiliser quelque chose comme ceci dans laravel-5.4:

Model::selectRaw("COUNT(*) views, DATE_FORMAT(created_at, '%Y %m %e') date")->groupBy('date')->get();
3
ako

Pour regrouper des données selon DATE au lieu de DATETIME, vous pouvez utiliser la fonction CAST.

$visitorTraffic = PageView::select('id', 'title', 'created_at')
->get()
->groupBy(DB::raw('CAST(created_at AS DATE)'));
2
gskhanal

Attention: code non testé.

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

Utiliser Laravel 4.2 sans carbone

Voici comment saisir les dix derniers jours et compter chaque ligne avec le même jour 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>';

}

J'espère que cela t'aides

1
btaylor507

dans mysql vous pouvez ajouter le mot clé MONTH ayant le paramètre timestamp

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

J'ai construit un paquet laravel pour faire des statistiques: https://github.com/Ifnot/statistics

Il est basé sur éloquent, carbone et indicateurs, il est donc très facile à utiliser. Cela peut être utile pour extraire les indicateurs groupés par date.

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

`` `

0
Ifnot

Je sais que c'est une vieille question et qu'il y a plusieurs réponses. Cependant, selon les docs et mon expérience sur laravel ci-dessous, c’est la bonne "méthode éloquente" de gestion

Dans votre modèle, ajoutez un mutateur/accélérateur comme celui-ci.

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

Une autre méthode consiste à convertir les colonnes. Dans votre modèle, remplissez le tableau $cast.

$casts = [
   'created_at' => 'string'
]

Le problème ici est que vous ne pourrez plus utiliser Carbon sur ce modèle car Eloquent transformera toujours la colonne en chaîne.

J'espère que ça aide :)

0
Sithira

Je résous le problème de cette façon. 

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