วิธีใช้ Laravel Collection ใน Cronjob สำหรับ Process ข้อมูล
หากคุณเคยเขียน Laravel Cronjob และต้องมานั่งเขียน loop ซ้ำๆ เพื่อ process ข้อมูล บทความนี้จะแนะนำวิธีใช้ Laravel Collection ร่วมกับ Cronjob ที่จะทำให้โค้ดของคุณสะอาดและอ่านง่ายขึ้นมาก
ทำไมต้องใช้ Laravel Collection ใน Cronjob?
ในการเขียน scheduled task หรือ cronjob สิ่งที่เราทำบ่อยๆ คือ:
- ดึงข้อมูลจาก database
- กรองข้อมูลบางส่วน
- คำนวณค่าต่างๆ
- สร้าง report
ถ้าเขียนแบบเดิมๆ เราจะต้องเขียน foreach หลายชั้น ทำให้โค้ดยาวและอ่านยาก แต่ถ้าใช้ Laravel Collection เราสามารถ chain methods ได้เลย ทำให้โค้ดกระชับและเข้าใจง่าย
// แบบเดิม - ยาวและอ่านยาก
$orders = Order::whereDate('created_at', today())->get();
$completed = [];
foreach ($orders as $order) {
if ($order->status === 'completed') {
$completed[] = $order;
}
}
$total = 0;
foreach ($completed as $order) {
$total += $order->amount;
}
// แบบ Collection - กระชับ
$total = Order::whereDate('created_at', today())
->get()
->filter(fn($o) => $o->status === 'completed')
->sum('amount');
พื้นฐาน Laravel Collection สำหรับ Cronjob
สร้าง Collection จาก Model
// ดึงข้อมูลมาเป็น Collection
$orders = Order::whereDate('created_at', today())->get();
// หรือสร้างจาก array
$collection = collect($data);
Method ที่ใช้บ่อยใน Cronjob
| Method | การใช้งาน |
|---|---|
filter() |
กรองข้อมูลตามเงื่อนไข |
map() |
แปลงข้อมูลแต่ละ item |
groupBy() |
จัดกลุ่มข้อมูล |
pluck() |
ดึงค่าเฉพาะ field |
sum(), avg(), count() |
คำนวณค่าต่างๆ |
first(), last() |
ดึง item แรก/สุดท้าย |
ตัวอย่างการใช้งานจริง: Daily Sales Report
สมมติว่าเราต้องการสร้างรายงานยอดขายประจำวัน โดย:
- ดึง orders ของวันนี้
- จัดกลุ่มตาม status
- คำนวณยอดรวมแต่ละ status
- ส่ง email รายงาน
ขั้นตอนที่ 1 – ดึงข้อมูล
$orders = Order::whereDate('created_at', today())->get();
ขั้นตอนที่ 2 – Process ด้วย Collection
$report = $orders
->groupBy('status')
->map(function ($group, $status) {
return [
'status' => $status,
'count' => $group->count(),
'total_amount' => $group->sum('amount'),
'avg_amount' => $group->avg('amount'),
];
})
->values(); // reset keys
ผลลัพธ์จะเป็น:
[
['status' => 'completed', 'count' => 150, 'total_amount' => 150000, 'avg_amount' => 1000],
['status' => 'pending', 'count' => 30, 'total_amount' => 25000, 'avg_amount' => 833],
['status' => 'cancelled', 'count' => 5, 'total_amount' => 2000, 'avg_amount' => 400],
]
ขั้นตอนที่ 3 – ส่ง Report
$message = $report->map(fn($r) => "- {$r['status']}: {$r['count']} orders, ฿{$r['total_amount']}")->join("\n");
Mail::to('[email protected]')->send(new DailyReport($message));
ใส่ใน Cronjob
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->dailyAt('08:00')->call(function () {
$orders = Order::whereDate('created_at', today())->get();
$report = $orders
->groupBy('status')
->map(fn($group, $status) => [
'status' => $status,
'count' => $group->count(),
'total_amount' => $group->sum('amount'),
])
->values();
Mail::to('[email protected]')->send(new DailyReport($report));
});
}
เทคนิคสำหรับข้อมูลขนาดใหญ่
ถ้าต้อง process ข้อมูลหลายแสน record ใน cronjob ต้องระวังเรื่อง memory usage
ใช้ chunk() แทน all()
// ❌ ดึงทั้งหมดมาพร้อมกัน - กิน memory
$orders = Order::all();
// ✅ แบ่งทีละ 100 records - ประหยัด memory
Order::where('processed', false)->chunk(100, function ($records) {
foreach ($records as $record) {
// process each record
}
});
ใช้ cursor() สำหรับ Memory Efficiency
// ใช้ cursor() สำหรับ iterate โดยไม่ต้องโหลดทั้งหมด
$total = 0;
foreach (Order::where('processed', false)->cursor() as $order) {
$total += $order->amount;
// process...
}
ใช้ lazy Collection
// lazy() จะไม่โหลดข้อมูลทั้งหมดมาก่อน
$collection = Model::where('status', 'active')->lazy()
->filter(fn($m) => $m->isValid())
->take(100);
สรุป
การใช้ Laravel Collection ใน Cronjob ช่วยให้:
- โค้ดสั้นลง – เขียน less, do more
- อ่านง่าย – chain methods ตามลำดับการทำงาน
- แก้ไขง่าย – เพิ่ม/ลด logic โดยไม่ต้องแก้ loop
- Test ได้ง่าย – Collection methods มี built-in testing helpers
ลองนำไปประยุกต์ใช้กับ cronjob ของคุณดูนะครับ 🚀