Laravel Carbon查询本月数据返回0结果,如何解决?
解决Laravel中获取用户本月数据的问题
你的问题主要出在两个关键点上:一是你在内存集合层面做筛选,而非数据库查询层面;二是日期比较的类型匹配可能出了问题。
正确解决方案
你需要调用$user->products()(这是Query Builder实例)来添加查询条件,让筛选逻辑在数据库层面执行,既高效又能避免类型问题。这里提供几种可靠的写法:
方法1:用时间范围精准限定本月(推荐)
利用Carbon的startOfMonth()和endOfMonth()直接划定本月的时间区间:
dd($user->products() ->where('paid', 1) ->whereBetween('created_at', [ Carbon::now()->startOfMonth(), Carbon::now()->endOfMonth() ]) ->get());
方法2:单独匹配年份和月份
通过whereYear和whereMonth精准定位当前月份:
dd($user->products() ->where('paid', 1) ->whereYear('created_at', Carbon::now()->year) ->whereMonth('created_at', Carbon::now()->month) ->get());
方法3:基于日期字符串筛选
如果只需要匹配日期部分,可以用whereDate:
dd($user->products() ->where('paid', 1) ->whereDate('created_at', '>=', Carbon::now()->startOfMonth()->toDateString()) ->get());
原代码返回0条结果的原因
- 集合筛选的低效与类型问题:你写的
$user->products会先把该用户所有产品加载到内存的Collection中,再用Collection的where方法筛选。这种方式不仅效率极低(数据量大时尤为明显),而且当created_at是Carbon实例时,和toDateString()返回的字符串日期比较,可能因类型不匹配导致筛选失效。 - 日期比较的类型不兼容:
Carbon::now()->startOfMonth()原本是带时间的Carbon对象(比如2024-05-01 00:00:00),你转成字符串后变成2024-05-01,集合中的created_at是Carbon对象,两者比较时无法自动完成类型转换,最终导致条件不成立。
而你用Carbon::now()->subMonth()能获取数据,是因为subMonth()返回的是Carbon对象,和集合中的Carbon类型created_at匹配,所以筛选有效,但这并不是你需要的“本月数据”范围。
内容的提问来源于stack exchange,提问作者Aleks Per
相关产品推荐
相关产品推荐

