Do not speak Portuguese? Translate this site with Google or Bing Translator
Calculating totals in Laravel using conditional aggregates

Posted on: January 29, 2020 12:18 PM

Posted by: Renato

Categories: Variados

Views: 420

Calculando totais no Laravel usando agregados condicionais

Calcular múltiplos totais (agregados) no Laravel da maneira mais eficiente. Por exemplo, talvez você tenha um serviço de assinatura de e-mail e queira exibir vários totais com base em seus inscritos:

Para o propósito deste artigo, digamos que temos uma tabela de banco de dados de assinantes com dados neste formato:

name email status
Adam Campbell [email protected] confirmed
Taylor Otwell [email protected] unconfirmed
Jonathan Reinink [email protected] cancelled
Adam Wathan [email protected] bounced

Idealmente, gostaríamos de calcular esses valores usando uma única consulta de banco de dados. No entanto, se você não tiver certeza de como fazer isso, você pode facilmente encontrar o caminho mais fácil e fazer isso:

$total = Subscriber::count();
$confirmed = Subscriber::where('status', 'confirmed')->count();
$unconfirmed = Subscriber::where('status', 'unconfirmed')->count();
$cancelled = Subscriber::where('status', 'cancelled')->count();
$bounced = Subscriber::where('status', 'bounced')->count();

Mas, claro, isso resultará em cinco consultas ao banco de dados, que sabemos que não são ótimas. Então você pode até tentar ser inteligente e resolver isso de outra maneira:

$subscribers = Subscriber::all();
$total = $subscribers->count();
$confirmed = $subscribers->where('status', 'confirmed')->count();
$unconfirmed = $subscribers->where('status', 'unconfirmed')->count();
$cancelled = $subscribers->where('status', 'cancelled')->count();
$bounced = $subscribers->where('status', 'bounced')->count();

Aqui estamos fazendo uma única consulta de banco de dados para obter todos os assinantes e, em seguida, executando contagens na coleção resultante. O problema é que essa abordagem é significativamente pior que a solução de várias consultas. Se nosso aplicativo tiver milhares ou milhões de inscritos, o tempo para processar todos os registros será lento e usará uma tonelada de memória.

Agregados condicionais

Na verdade, existe uma maneira realmente simples de calcular esses totais usando uma única consulta de banco de dados. O truque é colocar condições dentro de funções agregadas. Aqui está um exemplo no SQL:

select
count(*) as total,
count(case when status = 'confirmed' then 1 end) as confirmed,
count(case when status = 'unconfirmed' then 1 end) as unconfirmed,
count(case when status = 'cancelled' then 1 end) as cancelled,
count(case when status = 'bounced' then 1 end) as bounced from subscribers
total | confirmed | unconfirmed | cancelled | bounced
------+-----------+-------------+-----------+---------
  200 |       150 |          50 |        30 |   25

Veja como você pode escrever essa consulta no Laravel usando o construtor de consultas:

$totals = DB::table('subscribers')
    ->selectRaw('count(*) as total')
    ->selectRaw("count(case when status = 'confirmed' then 1 end) as confirmed")
    ->selectRaw("count(case when status = 'unconfirmed' then 1 end) as unconfirmed")
    ->selectRaw("count(case when status = 'cancelled' then 1 end) as cancelled")
    ->selectRaw("count(case when status = 'bounced' then 1 end) as bounced")
    ->first();

<div>Total: {{ $totals->total }}</div>
<div>Confirmed: {{ $totals->confirmed }}</div>
<div>Unconfirmed: {{ $totals->unconfirmed }}</div>
<div>Cancelled: {{ $totals->cancelled }}</div>
<div>Bounced: {{ $totals->bounced }}</div>

Boolean columns

Essa abordagem é ainda mais fácil se você estiver usando colunas booleanas. Um bom caso de uso para isso é totalizar diferentes funções dentro de um aplicativo.

$totals = DB::table('subscribers')
    ->selectRaw('count(*) as total')
    ->selectRaw('count(is_admin or null) as admins')
    ->selectRaw('count(is_treasurer or null) as treasurers')
    ->selectRaw('count(is_editor or null) as editors')
    ->selectRaw('count(is_manager or null) as managers')
    ->first();

Isso funciona porque o agregado count ignora as colunas nulas. Ao contrário do PHP, onde false ou null retorna false, no SQL (e JavaScript) ele retorna null. Basicamente, A ou B retorna o valor A se A puder ser coagido para true; caso contrário, retorna B.

Filter clauses

Finalmente, se você estiver usando o PostgreSQL, você também pode usar cláusulas de filtro para conseguir isso. Cláusulas de filtro são ótimas, pois permitem que você escreva suas condições usando cláusulas where normais. Além disso, com base em meus testes, as cláusulas de filtro são realmente mais rápidas do que as abordagens mencionadas acima.

$totals = DB::table('subscribers')
    ->selectRaw('count(*) as total')
    ->selectRaw('count(*) filter (where is_admin) as admins')
    ->selectRaw('count(*) filter (where is_treasurer) as treasurers')
    ->selectRaw('count(*) filter (where is_editor) as editors')
    ->selectRaw('count(*) filter (where is_manager) as managers')
    ->first();

Se você tiver alguma pergunta ou comentário sobre este artigo, envie-me (@cpdrenato) uma mensagem no Twitter. Eu adoraria ouvir de você.


0

Share

Donate to Site


About Author

Renato

Developer

Add a Comment
Comments 0 Comments

No comments yet! Be the first to comment

Blog Search


Categories

OUTROS (16) Variados (109) PHP (133) Laravel (171) Black Hat (3) front-end (29) linux (114) postgresql (39) Docker (28) rest (5) soap (1) webservice (6) October (1) CMS (2) node (7) backend (13) ubuntu (56) devops (25) nodejs (5) npm (3) nvm (1) git (8) firefox (1) react (7) reactnative (5) collections (1) javascript (7) reactjs (8) yarn (0) adb (1) Solid (2) blade (3) models (1) controllers (0) log (1) html (2) hardware (3) aws (14) Transcribe (2) transcription (1) google (4) ibm (1) nuance (1) PHP Swoole (5) mysql (31) macox (4) flutter (1) symfony (1) cor (1) colors (2) homeOffice (2) jobs (3) imagick (2) ec2 (1) sw (1) websocket (2) markdown (1) ckeditor (1) tecnologia (14) faceapp (1) eloquent (14) query (4) sql (40) ddd (3) nginx (9) apache (4) certbot (1) lets-encrypt (3) debian (12) liquid (1) magento (2) ruby (1) LETSENCRYPT (1) Fibonacci (1) wine (1) transaction (1) pendrive (1) boot (1) usb (1) prf (1) policia (2) federal (1) lucena (1) mongodb (4) paypal (1) payment (1) zend (1) vim (4) ciencia (6) js (1) nosql (1) java (1) JasperReports (1) phpjasper (1) covid19 (1) saude (1) athena (1) cinnamon (1) phpunit (2) binaural (1) mysqli (3) database (42) windows (6) vala (1) json (2) oracle (1) mariadb (4) dev (12) webdev (24) s3 (4) storage (1) kitematic (1) gnome (2) web (2) intel (3) piada (1) cron (2) dba (18) lumen (1) ffmpeg (2) android (2) aplicativo (1) fedora (2) shell (4) bash (3) script (3) lider (1) htm (1) csv (1) dropbox (1) db (3) combustivel (2) haru (1) presenter (1) gasolina (1) MeioAmbiente (1) Grunt (1) biologia (1) programming (22) performance (3) brain (1) smartphones (1) telefonia (1) privacidade (1) opensource (3) microg (1) iode (1) ssh (3) zsh (2) terminal (3) dracula (1) spaceship (1) mac (2) idiomas (1) laptop (2) developer (37) api (5) data (1) matematica (1) seguranca (2) 100DaysOfCode (9) hotfix (1) documentation (1) laravelphp (10) RabbitMQ (3) Elasticsearch (1) redis (2) Raspberry (4) Padrao de design (4) JQuery (1) angularjs (4) Dicas (43) Kubernetes (3) vscode (2) backup (1) angular (3) servers (2) pipelines (1) AppSec (1) DevSecOps (4) rust (1) RustLang (1) Mozilla (1) algoritimo (1) sqlite (1) Passport (2) jwt (5) security (2) translate (1) kube (2) iot (1) politica (2) bolsonaro (1) flow (1) podcast (1) Brasil (1) containers (3) traefik (1) networking (1) host (1) POO (2) microservices (2) bug (1) cqrs (1) arquitetura (3) Architecture (4) sail (3) militar (1) artigo (1) economia (1) forcas armadas (1) ffaa (1) autenticacao (2) autorizacao (2) authentication (4) authorization (3) NoCookies (1) wsl (4) memcached (1) macos (2) unix (2) kali-linux (1) linux-tools (5) apple (1) noticias (2) composer (1) rancher (1) k8s (1) escopos (1) orm (1) jenkins (4) github (5) gitlab (3) queue (1) Passwordless (1) sonarqube (1) phpswoole (1) laraveloctane (1) Swoole (1) Swoole (1) octane (1) Structurizr (1) Diagramas (1) c4 (1) c4-models (1) compactar (1) compression (1) messaging (1) restfull (1) eventdrive (1) services (1) http (1) Monolith (1) microservice (1) historia (1) educacao (1) cavalotroia (1) OOD (0) odd (1) chatgpt (1) openai (3) vicuna (1) llama (1) gpt (1) transformers (1) pytorch (1) tensorflow (1) akitando (1) ia (1) nvidia (1) agi (1) guard (1) multiple_authen (2) rpi (1) auth (1) auth (1) livros (2) ElonMusk (2) Oh My Zsh (1) Manjaro (1) BigLinux (2) ArchLinux (1) Migration (1) Error (1) Monitor (1) Filament (1) LaravelFilament (1) replication (1) phpfpm (1) cache (1) vpn (1) l2tp (1) zorin-os (1) optimization (1) scheduling (1) monitoring (2) linkedin (1) community (1) inteligencia-artificial (2) wsl2 (1) maps (1) API_KEY_GOOGLE_MAPS (1) repmgr (1) altadisponibilidade (1) banco (1) modelagemdedados (1) inteligenciadedados (4) governancadedados (1) bancodedados (2) Observability (1) picpay (1) ecommerce (1) Curisidades (1) Samurai (1) KubeCon (1) GitOps (1) Axios (1) Fetch (1) Deepin (1) vue (4) nuxt (1) PKCE (1) Oauth2 (2) webhook (1) TypeScript (1) tailwind (1) gource (2)

New Articles



Get Latest Updates by Email