Como Criar Relatórios PDF a Partir de Dados do Banco de Dados — TongoRender Blog
Voltar ao Blog
tutorialsreportsdatabaseautomation

Como Criar Relatórios PDF a Partir de Dados do Banco de Dados

Aprenda a conectar a um banco de dados, consultar dados, construir um relatório HTML e convertê-lo em um PDF profissional usando uma API. Inclui exemplos de código passo a passo em Node.js.

TongoRender Team18 de março de 202611 min

Gerar relatórios PDF a partir de dados do banco de dados é uma das tarefas mais comuns em aplicações empresariais. Seja construindo um dashboard que exporta análises mensais, um CRM que produz resumos de clientes ou um sistema ERP que imprime relatórios de inventário, o fluxo de trabalho é fundamentalmente o mesmo: consultar o banco de dados, transformar os resultados em HTML e renderizar esse HTML como PDF.

Neste tutorial, vamos percorrer todo o processo usando Node.js, PostgreSQL e a API HTML-para-PDF do TongoRender.

A Arquitetura

Antes de mergulhar no código, vamos delinear o fluxo de dados:

  1. Consulta — Conecte ao banco de dados e busque os dados necessários para o relatório.
  2. Transformação — Mapeie os resultados da consulta em um template HTML com tabelas, gráficos e estatísticas resumidas.
  3. Renderização — Envie o HTML para uma API que o converte em PDF.
  4. Entrega — Salve o PDF em disco, faça upload para armazenamento em nuvem ou envie por email ao destinatário.

Passo 1: Configurando a Conexão com o Banco de Dados

Vamos usar a biblioteca pg para conectar ao PostgreSQL. Instale as dependências:

npm install pg dotenv node-fetch

Crie um helper para o banco de dados:

// db.js
const { Pool } = require('pg');
require('dotenv').config();

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
});

async function query(text, params) {
  const result = await pool.query(text, params);
  return result.rows;
}

module.exports = { query };

Passo 2: Consultando os Dados do Relatório

Suponha que queremos um relatório mensal de vendas. Precisamos de receita total, contagem de pedidos, produtos mais vendidos e um detalhamento diário:

// reports/monthly-sales.js
const { query } = require('../db');

async function getMonthlySalesData(year, month) {
  const startDate = new Date(year, month - 1, 1);
  const endDate = new Date(year, month, 0);

  const [summary] = await query(
    `SELECT COUNT(*) as order_count,
            SUM(total) as revenue,
            AVG(total) as avg_order_value
     FROM orders
     WHERE created_at BETWEEN $1 AND $2`,
    [startDate, endDate]
  );

  const topProducts = await query(
    `SELECT p.name, SUM(oi.quantity) as units_sold, SUM(oi.subtotal) as revenue
     FROM order_items oi
     JOIN products p ON p.id = oi.product_id
     JOIN orders o ON o.id = oi.order_id
     WHERE o.created_at BETWEEN $1 AND $2
     GROUP BY p.name
     ORDER BY revenue DESC
     LIMIT 10`,
    [startDate, endDate]
  );

  return { summary, topProducts };
}

Passo 3: Construindo o Template HTML

Agora transformamos os dados em um documento HTML bem estruturado com CSS amigável para impressão:

function buildReportHTML(data, year, month) {
  const monthName = new Date(year, month - 1).toLocaleString('pt-BR', { month: 'long' });

  return `
  <!DOCTYPE html>
  <html lang="pt-BR">
  <head>
    <style>
      body { font-family: 'Helvetica Neue', sans-serif; color: #1a1a2e; margin: 40px; }
      h1 { color: #16213e; border-bottom: 3px solid #0f3460; padding-bottom: 10px; }
      .summary-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin: 20px 0; }
      .summary-card { background: #f0f4ff; border-radius: 8px; padding: 20px; text-align: center; }
      .summary-card .value { font-size: 2em; font-weight: 700; color: #0f3460; }
      table { width: 100%; border-collapse: collapse; margin: 20px 0; }
      th { background: #0f3460; color: white; padding: 10px; text-align: left; }
      td { padding: 10px; border-bottom: 1px solid #e0e0e0; }
    </style>
  </head>
  <body>
    <h1>Relatório de Vendas — ${monthName} ${year}</h1>
    <div class="summary-grid">
      <div class="summary-card">
        <div class="value">${data.summary.order_count}</div>
        <div>Total de Pedidos</div>
      </div>
      <div class="summary-card">
        <div class="value">R$ ${Number(data.summary.revenue).toLocaleString('pt-BR')}</div>
        <div>Receita</div>
      </div>
      <div class="summary-card">
        <div class="value">R$ ${Number(data.summary.avg_order_value).toFixed(2)}</div>
        <div>Valor Médio do Pedido</div>
      </div>
    </div>

    <h2>Produtos Mais Vendidos</h2>
    <table>
      <thead><tr><th>Produto</th><th>Unidades</th><th>Receita</th></tr></thead>
      <tbody>
        ${data.topProducts.map(p => \`
          <tr><td>${p.name}</td><td>${p.units_sold}</td><td>R$ ${Number(p.revenue).toLocaleString('pt-BR')}</td></tr>
        \`).join('')}
      </tbody>
    </table>
  </body>
  </html>`;
}

Passo 4: Convertendo para PDF com o TongoRender

Com o HTML pronto, uma única chamada de API produz o PDF:

async function generateReport(year, month) {
  const data = await getMonthlySalesData(year, month);
  const html = buildReportHTML(data, year, month);

  const response = await fetch('https://api.tongorender.io/v1/pdf', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.TONGORENDER_API_KEY,
    },
    body: JSON.stringify({
      html,
      format: 'A4',
      margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
    }),
  });

  if (!response.ok) throw new Error(`Erro da API: ${response.statusText}`);
  return Buffer.from(await response.arrayBuffer());
}

Agendando Relatórios com Cron

Automatize a geração de relatórios agendando um job cron que executa no primeiro dia de cada mês:

const cron = require('node-cron');

cron.schedule('0 8 1 * *', async () => {
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth();
  const pdf = await generateReport(year, month);
  await uploadToS3(pdf, `reports/${year}-${String(month).padStart(2, '0')}.pdf`);
  await sendEmail('financeiro@empresa.com', 'Relatório Mensal de Vendas', pdf);
});

Dicas para Relatórios de Qualidade

  • Trate dados vazios com elegância — Mostre mensagens "Sem dados disponíveis" em vez de tabelas vazias.
  • Formate números consistentemente — Use Intl.NumberFormat para moeda e números grandes.
  • Adicione timestamps — Inclua a data de geração e o período no cabeçalho do relatório.
  • Use pool de conexões — O pg.Pool gerencia conexões eficientemente para requisições concorrentes.

O TongoRender torna a etapa de renderização do PDF sem esforço. Concentre-se em consultar os dados certos e projetar um template claro — a API cuida do resto.

Comece a gerar relatórios com o TongoRender — 100 renderizações gratuitas por mês, sem necessidade de cartão de crédito.

Compartilhe este artigoCompartilhar no Twitter