如何用Laravel的firstOrCreate仅按Y-m-d日期判断新增记录?
Laravel按日期(不含时分秒)实现firstOrCreate逻辑的方法
问题原因
你之前的做法失效,核心原因是created_at一般为datetime/timestamp类型:当你传入Y-m-d格式的Carbon日期时,Laravel会自动补全时分秒为00:00:00,导致只有数据库中created_at恰好是当天零点的记录才会被匹配到,其他时间的记录都无法命中,所以每次都会新增。
解决方案
方法一:先查询再创建(最稳妥直接)
用whereDate方法精准匹配日期部分,找不到记录时再创建:
use Carbon\Carbon; use App\Models\YourModel; // 替换为你的实际模型类 $userEmail = 'user@example.com'; $today = Carbon::today(); // 查询当天该用户的记录 $record = YourModel::where('user_email', $userEmail) ->whereDate('created_at', $today) ->first(); // 无匹配记录则创建新条目 if (!$record) { $record = YourModel::create([ 'user_email' => $userEmail, 'created_at' => Carbon::now(), // 也可根据需求设为Carbon::today() // 其他需要填充的字段 ]); }
方法二:封装查询范围(提升复用性)
在模型中定义查询范围,简化重复调用逻辑:
// 在你的模型类中添加 public function scopeForUserAndDate($query, $userEmail, $date) { return $query->where('user_email', $userEmail) ->whereDate('created_at', $date); }
使用时的代码会更简洁:
$record = YourModel::forUserAndDate('user@example.com', Carbon::today()) ->first() ?? YourModel::create([ 'user_email' => 'user@example.com', 'created_at' => Carbon::now(), // 其他字段 ]);
方法三:结合原生SQL函数(贴近firstOrCreate写法)
针对MySQL数据库,可以用DATE()函数提取日期部分作为查询条件,结合firstOrCreate:
$record = YourModel::firstOrCreate( [ 'user_email' => 'user@example.com', \Illuminate\Support\Facades\DB::raw('DATE(created_at)') => Carbon::today()->toDateString(), ], [ // 新增记录时的默认字段配置 'created_at' => Carbon::now(), ] );
注意:不同数据库的日期转换函数不同,比如PostgreSQL需用
CAST(created_at AS DATE),请根据你的数据库类型调整。
内容的提问来源于stack exchange,提问作者sfarzoso
相关产品推荐
相关产品推荐

