Laravel Eloquent whereIn,从数据库中检索记录,包括缺失日期
Laravel Eloquent whereIn, retrieving records from database including for missing dates
我是 Laravel 的新手。
我正在构建可以计算您每日步数的应用程序。
我正在构建 API,所以当数据库中没有数组中所选日期的结果时,我需要 return 0 个步骤。
但是,如果某些天的数据为 return 实际步数,而其他天为 return 0。
我试过这个:
$steps = Step::whereIn('date', $dates)
->where('user_id', Auth::id())
->get();
但它 return 只匹配。正如我所写的,我想要 return 所有天的数据,而不仅仅是数据库中的天数。请帮忙 :)
这对于一个简单的查询来说是不可能的,因为数据库不能给你任何东西,它不知道。
您可以通过编程方式解决此问题,即迭代结果并添加所有具有 0 值的缺失日期,或者通过将 table 添加到包含所有日期的数据库,然后在 table 中加入您的步骤查询。
实际上,对于您列出的所有日期,您必须有一个 table。因为只有 table 中存在记录才能获取日期。另一种选择是在 PHP 中为所有日期创建一个循环,但这会产生大量查询,这不是最佳解决方案。
如果您有一个日期 table,您可以将它与您的步骤 table 结合起来,并且可以使用 COALESCE 命令。我建议您将查询编写为纯 SQL,然后将其转换为 Eloquent 查询。
如果您不想将缺失日期的空记录添加到数据库中
这样会头疼:
$dates = [
'2016-12-01',
'2016-12-02',
...
'2016-12-31'
];
$records = Step::whereIn('date', $dates)
->where('user_id', Auth::id())
->get();
$steps = [];
$dates = array_flip($dates); // flipping array like: ['2016-12-01' => 0, '2016-12-02' => 1, ...]
foreach($records AS $record) { // iterating records
$steps[] = $record; // collecting records
unset($dates[$record->date]); // removing date that has record for that day
}
$dates = array_flip($dates); // flipping back: [0 => '2016-12-01', ...]
foreach($dates as $date) { // iterating dates that do not have data in db and creating model objects from them
// creating missing record "on the fly"
$Step = new Step([
'date' => $date,
'user_id' => Auth::id(),
'steps' => 0
]);
$Step->save();
$steps[] = $Step; // adding model instance to resulting array
}
usort($steps, function($a, $b) { // sorting array of steps by date
if(strtotime($a->date) > strtotime($b->date)) return 1;
if(strtotime($a->date) < strtotime($b->date)) return -1;
return 0;
});
所以我的建议是有一些控制台命令(/app/Console/Commands/
)每晚都会进行处理并确保所有记录都是一致的。
我的意思是创建一些后台批处理进程 "close the day" 并在用户没有该日期的记录时在数据库中创建一些记录。
此建议简化了一切,因此您的控制器将像往常一样获取数据,而无需任何额外的计算、迭代等。
我是 Laravel 的新手。
我正在构建可以计算您每日步数的应用程序。
我正在构建 API,所以当数据库中没有数组中所选日期的结果时,我需要 return 0 个步骤。
但是,如果某些天的数据为 return 实际步数,而其他天为 return 0。
我试过这个:
$steps = Step::whereIn('date', $dates)
->where('user_id', Auth::id())
->get();
但它 return 只匹配。正如我所写的,我想要 return 所有天的数据,而不仅仅是数据库中的天数。请帮忙 :)
这对于一个简单的查询来说是不可能的,因为数据库不能给你任何东西,它不知道。 您可以通过编程方式解决此问题,即迭代结果并添加所有具有 0 值的缺失日期,或者通过将 table 添加到包含所有日期的数据库,然后在 table 中加入您的步骤查询。
实际上,对于您列出的所有日期,您必须有一个 table。因为只有 table 中存在记录才能获取日期。另一种选择是在 PHP 中为所有日期创建一个循环,但这会产生大量查询,这不是最佳解决方案。
如果您有一个日期 table,您可以将它与您的步骤 table 结合起来,并且可以使用 COALESCE 命令。我建议您将查询编写为纯 SQL,然后将其转换为 Eloquent 查询。
如果您不想将缺失日期的空记录添加到数据库中
这样会头疼:
$dates = [
'2016-12-01',
'2016-12-02',
...
'2016-12-31'
];
$records = Step::whereIn('date', $dates)
->where('user_id', Auth::id())
->get();
$steps = [];
$dates = array_flip($dates); // flipping array like: ['2016-12-01' => 0, '2016-12-02' => 1, ...]
foreach($records AS $record) { // iterating records
$steps[] = $record; // collecting records
unset($dates[$record->date]); // removing date that has record for that day
}
$dates = array_flip($dates); // flipping back: [0 => '2016-12-01', ...]
foreach($dates as $date) { // iterating dates that do not have data in db and creating model objects from them
// creating missing record "on the fly"
$Step = new Step([
'date' => $date,
'user_id' => Auth::id(),
'steps' => 0
]);
$Step->save();
$steps[] = $Step; // adding model instance to resulting array
}
usort($steps, function($a, $b) { // sorting array of steps by date
if(strtotime($a->date) > strtotime($b->date)) return 1;
if(strtotime($a->date) < strtotime($b->date)) return -1;
return 0;
});
所以我的建议是有一些控制台命令(/app/Console/Commands/
)每晚都会进行处理并确保所有记录都是一致的。
我的意思是创建一些后台批处理进程 "close the day" 并在用户没有该日期的记录时在数据库中创建一些记录。
此建议简化了一切,因此您的控制器将像往常一样获取数据,而无需任何额外的计算、迭代等。