Laravel如何实现数据统计的年度折线图?(报表开发)

7次阅读

eloquent 按年分组统计需用 selectraw(‘year(created_at) as year’) + groupby,避免 php 端处理;配合 sum()、orderby(‘year’)、pluck 转标准图表结构,并注意索引优化与时区对齐。

Laravel如何实现数据统计的年度折线图?(报表开发)

用 Eloquent 按年分组统计数据

折线图的横轴是年份,纵轴是数值,核心是把原始数据按 year 聚合。laravel 自带的 selectRaw + groupBy 就够用,不需要手写原生 sql

常见错误是直接用 created_at->year,但这是 PHP 端操作,无法在数据库层面分组,会导致全量查出再 PHP 循环——数据一多就卡死或内存溢出。

  • mysqlYEAR(created_at)postgresqlEXTRACT(YEAR FROM created_at)
  • Laravel 8+ 推荐统一用 selectRaw('YEAR(created_at) as year'),避免方言差异
  • 记得加 orderBy('year'),否则前端画图时年份顺序乱
  • 如果统计的是订单金额,别漏掉 sum('amount'),而不是只 count(*)
$data = Order::selectRaw('YEAR(created_at) as year')     ->selectRaw('SUM(amount) as total')     ->whereBetween('created_at', ['2020-01-01', now()])     ->groupBy('year')     ->orderBy('year')     ->get();

前端图表库怎么接 Laravel 返回的数据

后端返回的 $dataCollection,直接 json_encode 给前端就行,但要注意键名是否匹配图表库要求(比如 Chart.js 要 labelsdatasets[0].data)。

容易踩的坑是没做 key 映射,比如后端字段叫 yeartotal,前端却硬写成 labelvalue,结果图表空白。

  • 推荐在控制器里提前转成标准结构:['labels' => $data->pluck('year'), 'data' => $data->pluck('total')]
  • 不要用 toArray() 后再手动遍历——Collection 的 pluck 更安全、更少出错
  • 如果年份有空缺(比如 2021 年没数据),Chart.js 不会自动补 0,得后端补全或前端用 Array.from({Length: 5}) 对齐

性能瓶颈常出现在时间范围过大或关联查询上

当统计跨度超过 5 年、单表记录超百万时,GROUP BY YEAR(created_at) 可能走不了索引,尤其 created_at 没建索引或用了函数导致索引失效。

不是所有数据库都支持函数索引,MySQL 5.7+ 才支持函数索引,而且得显式创建:

  • 先确认 created_at 字段有索引:SHOW INDEX FROM orders WHERE Key_name = 'idx_created_at'
  • MySQL 8.0+ 可建函数索引:CREATE INDEX idx_year ON orders (YEAR(created_at))
  • 更稳妥的做法是加一个生成列 year 并索引它,避免函数依赖
  • 如果还连了 user 表做统计(比如按用户注册年份+下单年份双维度),务必用 withCount 或子查询,别用 join + groupBy,容易重复计数

为什么不用 Laravel Scout 或 Telescope 做这类统计

Scout 是搜索,Telescope 是调试,它们都不处理聚合计算。有人误以为 “Laravel 有现成报表包”,其实官方没提供开箱即用的统计图表组件——它只负责把数据干净地查出来。

真正省事的方式是:后端只管按年聚合、返回 json;前端用 Chart.js 或 ApexCharts 渲染。中间不加任何“报表中间件”或“统计服务类”,越简单越稳定。

复杂点在于年份对齐和时区——created_at 存的是 UTC,但业务要按本地年份统计(比如中国用户说的“2024 年”是东八区),得在查询前把时间范围转成 UTC,或者在数据库层用 CONVERT_TZ 处理。这点很容易被忽略,一到年底就发现 12 月数据少一半。

text=ZqhQzanResources