استفاده از توابع aggregation در لاراول

?>

دسترسی سریع به عناوین این مقاله

تصور کنید که یک پروژه لاراولی دارید که لیست درخواست های یک سیستم تیکت را به همراه وضعیت هر درخواست نمایش میدهد.

کارفرما از شما درخواست میکند که در بالای صفحه 3 کادر طراحی کنید که داخل هر کادر تعداد کل درخواست ها، انجام شده، در حال پیگیری را نشان دهد.

FvCM3PoKuoigEerfKZjhBLRY6Wp1cgHXEAIbKg1G - استفاده از توابع aggregation در لاراول - aggregation, laravel, توابع aggregation, توابع aggregation در لاراول, لاراول
لیست درخواستهای تیکت

خب!

حالا چطور به بهترین روش ممکن این تعداد ها را دریافت کنیم؟

یک راهکار این است که چند کوئری جداگانه به دیتابیس بزنیم که تعداد درخواست های هر وضعیت را حساب کند. این راه را امتحان می کنیم.

public function index()

{
    $statuses = (object)[];
    $statuses->requested = Feature::where('status','requested')->count();
    $statuses->planned = Feature::where('status','planned')->count();
    $statuses->completed = Feature::where('status','completed')->count();

    $features = Feature::query()
        ->withCount('comments')
        ->paginate();

    return view('features', [
        'statuses' => $statuses,
        'features' => $features,
    ]);

}

اگر به کدهای بالا نگاه کنیم، سه کوئری ای که برای به دست آوردن تعداد ها زده ایم را می بینیم که در این شرایط مشکل خاصی نیست چون تنها سه وضعیت داریم.

اما اگر 5 وضعیت داشتیم چه؟ یا 10 یا حتی بیشتر از آن. این همان وقتی است که کوئری های جدا مشکل ایجاد می کنند.

می خواهم به شما تکنیکی که در توابع aggregation در لاراول است و در این شرایط استفاده می کنم را نشان دهم.

توابع aggregation در لاراول

به سراغ یک ابزار مدیریت دیتابیس مانند table plus یا PhpMyadmin یا Navicat بروید تا کوئری را آن جا به دست آوریم. (خودم از navicate استفاده میکنم)

 در اصل راهی وجود دارد که بتوانیم این تعداد ها را با یک کوئری به دست آوریم. احتمالا با نوشتن کوئری ای مانند زیر آشنایی دارید.

SELECT COUNT(*) from features

اگر این کوئری را اجرا کنید نتیجه آن 60 خواهد بود.

 چیزی که احتمالا نمی دانید این است که می توان دستورهای شرطی را داخل توابعی مانند COUNT و SUM و… نوشت. به کوئری بالا شرط اضافه می کنیم. 

SELECT COUNT(CASE WHEN status = 'Requested' THEN 1 END) from features

اگر کوئری بالا را اجرا کنیم نتیجه آن 47 خواهد بود. اگر به صفحه  اصلی برنامه نگاه کنیم می بینیم که این مقدار درست است. حال یک شرط دیگر اضافه می کنیم.

SELECT 
COUNT(CASE WHEN status = 'Requested' THEN 1 END),
COUNT(CASE WHEN status = 'Planned' THEN 1 END)
from features

اگر این کوئری را اجرا کنیم دو تعداد در نتیجه می گیریم 47 و 3 که هر دو درست اند. این کار را برای وضعیت سوم هم انجام می دهیم.

SELECT 
COUNT(CASE WHEN status = 'Requested' THEN 1 END),
COUNT(CASE WHEN status = 'Planned' THEN 1 END),
COUNT(CASE WHEN status = 'Completed' THEN 1 END)
from features

با اجرای کوئری بالا این نتیجه را دریافت می کنیم.

pCJEvtGJD8WakrVcQS11GpVS9M0emOnrjp71UUoi - استفاده از توابع aggregation در لاراول - aggregation, laravel, توابع aggregation, توابع aggregation در لاراول, لاراول

جمع این سه عدد 60 می شود که تعداد کل درخواست ها بود. البته در حال حاضر اسم ستون هایی که در نتیجه آمده اند خوب نیست. به همین خاطر به هر کدام از آن ها یک نام مستعار می دهیم.

SELECT 
COUNT(CASE WHEN status = 'Requested' THEN 1 END) as requested,
COUNT(CASE WHEN status = 'Planned' THEN 1 END) as planned,
COUNT(CASE WHEN status = 'Completed' THEN 1 END) as completed
from features

اکنون نتیجه ای مانند زیر دریافت می شود.

- استفاده از توابع aggregation در لاراول - aggregation, laravel, توابع aggregation, توابع aggregation در لاراول, لاراول

حال به کنترلر FeatureController می رویم تا کوئری را در آنجا بنویسیم.

public function index()

{
    $statuses = Feature::toBase()
        ->selectRaw("count(case when status = 'Requested' then 1 end) as requested")
        ->selectRaw("count(case when status = 'Planned' then 1 end) as planned")
        ->selectRaw("count(case when status = 'Completed' then 1 end) as completed")
        ->first();

    $features = Feature::query()
        ->withCount('comments')
        ->paginate();

    return view('features', [
        'statuses' => $statuses,
        'features' => $features,
    ]);

}

به این دلیل که نمی خواهیم نتیجه دریافتی یک شی از مدل Feature باشد متد toBase را صدا زدیم (با اجرای این متد مدل به دست آمده به شی ای از  query builder تبدیل می شود). سپس از متد selectRaw برای نوشتن کوئری استفاده کردیم و در نهایت از آن جایی که می دانیم این کوئری تنها یک row بر می گرداند متد first را به جای get صدا زدیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *