Usando a função Postgres::array_agg para agregar colunas de string

Jan 12, 2021 1 min reading
  • Tags:
  • postgres
  • array
  • agg
  • function
  • sqlalchemy

Graças a @copquevictor eu aprendi uma função de agregação muito útil do Posgres: array_agg. Para entendê-la, vamos supor que você tenha que notificar interessados em relatórios e sua query fornece a tabela abaixo como saída:

| Report    | Email                  |
| --------- | ---------------------- |
| Report #1 | johndoe@gmail.com      |
| Report #1 | jack@gmail.com         |
| Report #2 | contact@lisadesign.com |
| Report #3 | harry@hogwarts.com     |
| Report #3 | anderson@gmail.com     |

Como você pode ver, nós temos uma relação Um-para-Muitos: um relatório é de interesse de um ou mais emails. Você pode notificar os emails por meio (i) da iteração dos registros (um por um) OU (ii) você pode agrupar os emails por relatório. Para o segundo caso, não seria legal obter os resultados abaixo?

| Report    | Email                                    |
|-----------|------------------------------------------|
| Report #1 | [johndoe@gmail.com, jack@gmail.com]      |
| Report #2 | [contact@lisadesign.com]                 |
| Report #3 | [harry@hogwarts.com, anderson@gmail.com] |

Graças a array_agg isso pode ser realizado. Para nossa tabela fictícia, a query seria algo parecido com a query abaixo:

SELECT reports.id, array_agg(stakeholders.email) FROM reports
INNER JOIN stakeholders ON reports.id = stakeholders.report_id
GROUP BY reports.id;

Preste atenção que você tem que fornecer a cláusula GROUP BY a fim de agregar os emails.

from sqlalchemy import String
from sqlalchemy.sql.functions import array_agg
from sqlalchemy.dialects.postgresql import ARRAY

from models import Stakeholder, Report

def execute():
    emails_agg = array_agg(Stakeholder.email, type_=ARRAY(String)).label(
        "emails"
    )
    return (
        db.session.query(Report, emails_agg)
        .join(Stakeholder)
        .group_by(Report.id)
        .all()
    )

Bem útil, não acha?

Referências:

* Featured image credits: Nam Anh

Comments