Laravel 查询获取尚未存在真实数据的日期的虚拟数据

Posted

技术标签:

【中文标题】Laravel 查询获取尚未存在真实数据的日期的虚拟数据【英文标题】:Laravel query get dummy data for days where no real data exists yet 【发布时间】:2021-07-26 03:30:47 【问题描述】:

我的 Laravel 项目中有一个查询,它从我的数据库中返回两个日期之间的数据集合,然后按小时分组(但我可以根据自己的喜好更改),我现在想返回数据存在于数据库中之前的“日期”作为构建日期列表的一种方式,可以在我的网页中显示,即使这些天没有数据,我的图表看起来还是一致的。

举个例子:

我想查看过去 30 天的数据作为历史记录,但是这段时间的前 20 天还没有数据,我仍然需要返回这些天的日期键,除了其中没有数据。

我目前的代码如下(我用的是Carbon):

$uptimeData = UptimeChecks::where('user_id', 1)
                        ->where('monitor_id', 1)
                        ->where('checked_at', '>=', '2021-01-01 00:00:00')
                        ->where('checked_at', '<=', '2021-01-30 23:59:59')
                        ->orderBy('checked_at', 'asc')
                        ->select('event', 'checked_at')
                        ->get();

$from = Carbon::now()->subDays(60);
$period = CarbonPeriod::create($from, '2021-01-30 23:59:59');
$dates = $period->toArray();

foreach ($dates as $key => $date) 
  $dates[$key] = Carbon::parse($date)->format('Y-m-d');


$uptimeData = collect($uptimeData);
$uptimeData = $uptimeData->merge($dates);

$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) 

  if (isset($item->checked_at)) 
    $date = Carbon::parse($item->checked_at);
   else 
    $date = Carbon::parse($item);
  

  return $date->format('Y-m-d');
);

即使没有显示“checked_at”列的条目,这是否可以在没有数据的情况下用当天的日期进行欺骗?

更新 03/05 @ 20:30

我已经更新了我的描述以反映解决此问题的最新尝试,我似乎已经构建了我需要的东西,但是有一些问题:

    我在哪里循环我的$dates 有没有办法在每个项目中建立一些结构,这样我就不必对我的所有变量和键进行if/else 检查? 由于某种原因,在真实数据之后添加了“假”虚拟日期,例如:1 月 1 日、1 月 2 日、12 月 30 日......我该如何扭转这种情况?

【问题讨论】:

您可以构建一个集合,其中包含您想要的所有日期(如果对视图有用,可能使用默认值),然后将查询结果与其合并。 看起来怎么样? @mikenewbuild 在我的手机上,很难打出来,这里是建立日期范围的方法***.com/a/50854594,这里是你可以在集合上使用的合并方法laravel.com/docs/8.x/collections#method-merge 您应该只获取数据库中实际存在的数据。对于您的场景,您可以在控制器中编写代码,您可以在其中添加空日期以制作所需的格式。 @mikenewbuild 我已经用我相信你所指的内容更新了我的描述,但现在我的数组中没有任何东西?我错过了什么? 【参考方案1】:

实现此目的的一种方法是创建所需时间段的日期集合,然后将按日期分组的查询结果合并到其中。

这是一个例子:


$from = '2021-01-01';
$to = '2021-01-31';

$period = CarbonPeriod::create($from, $to);
$dates = collect($period->toArray())->mapWithKeys(function ($date) 
  return [$date->format('Y-m-d') => []];
);

// $dates = ['2021-01-01' => [], '2021-01-02' => [], ...etc]

$uptimeChecks = UptimeChecks::query()
    ->where('user_id', 1)
    ->where('monitor_id', 1)
    ->whereBetween('checked_at', [$from, $to])
    ->orderBy('checked_at', 'asc')
    ->select('event', 'checked_at')
    ->get();

$uptimeDates = $uptimeChecks->groupBy(function ($item, $key) 
  return $item->checked_at->format('Y-m-d');
);

// $uptimeDates = ['2021-01-02' => ['event1', 'event2'], ...etc]

$uptimeData = $dates->merge($uptimeDates);

// $uptimeData = ['2021-01-01' => [], '2021-01-02' => ['event1', 'event2'], ...etc]

这假设您将 checked_at 字段转换为 UptimeChecks 模型中的日期。

【讨论】:

NP,很高兴它解决了它! Ps 我注意到你的 UptimeChecks 模型是复数,但惯例是它是单数 UptimeCheck 是的,那是因为当您从数据库中获取多条记录时,例如使用 UptimeChecks::where()-&gt;get() 似乎是合乎逻辑的,其中单数听起来适合像 UptimeCheck::first() 这样的单个正常运行时间检查,你有什么想法? 一个模型(大致)被设计为代表数据库中的一行,如果你使用first(),你会得到一个UptimeCheck的实例,当你运行get()你会得到一个Collection(不是模型)可以不包含UptimeCheck 的多个实例或多个实例,所以我总是对模型使用单数。

以上是关于Laravel 查询获取尚未存在真实数据的日期的虚拟数据的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 查询不使用 where 子句作为日期

在 Laravel 中添加时间到日期查询

Laravel 获取连接表的最近日期

在Laravel中获取所选查询的平均日期

Laravel 5 如何更新最新数据并获取数据库的真实累积和

从 Laravel 中的日期列查询两个日期之间的数据