Pular para conteúdo

POSTGRESQL UPDATE - Atualizar Registro

O que é este Node?

O POSTGRESQL UPDATE é o node responsável por atualizar registros existentes em tabelas PostgreSQL de forma segura usando prepared statements.

Por que este Node existe?

Atualizar dados é operação essencial em aplicações. O POSTGRESQL UPDATE existe para:

  1. Segurança: Usa prepared statements prevenindo SQL injection
  2. Condicional: Atualiza apenas registros que atendem condições WHERE
  3. Múltiplos campos: Atualiza vários campos em uma única operação
  4. RETURNING: Retorna registros atualizados com novos valores
  5. Validação: Valida campos antes de executar
  6. Performance: Otimizado para updates estruturados

Como funciona internamente?

Quando o POSTGRESQL UPDATE é executado, o sistema:

  1. Valida config: Verifica credenciais PostgreSQL
  2. Substitui variáveis: Troca {{variavel}} em values e conditions
  3. Monta SQL: Cria UPDATE com placeholders ($1, $2...) seguros
  4. Aplica WHERE: Adiciona cláusula WHERE com conditions
  5. Executa: Envia para PostgreSQL com valores parametrizados
  6. Retorna: Devolve registros atualizados (RETURNING *) e rowCount
  7. Se erro: Lança exceção (registro não existe, constraint violation)

Código interno (postgresql.executor.ts:126-154):

private async updateRow(
  pool: Pool,
  table: string,
  fields: string[],
  values: Record<string, any>,
  conditions: Record<string, any>,
  context: ExecutionContext,
): Promise<any> {
  const replacedValues = this.replaceObjectVariables(values, context.variables);
  const replacedConditions = this.replaceObjectVariables(conditions, context.variables);

  const setClause = Object.keys(replacedValues)
    .map((key, i) => `${key} = $${i + 1}`)
    .join(', ');

  const whereClause = Object.keys(replacedConditions)
    .map((key, i) => `${key} = $${Object.keys(replacedValues).length + i + 1}`)
    .join(' AND ');

  const valueArray = [...Object.values(replacedValues), ...Object.values(replacedConditions)];

  const query = `UPDATE ${table} SET ${setClause} WHERE ${whereClause} RETURNING *`;
  const result = await pool.query(query, valueArray);

  return {
    updatedRows: result.rows,
    rowCount: result.rowCount,
  };
}

Quando você DEVE usar este Node?

Use POSTGRESQL UPDATE quando precisar atualizar registros existentes:

Casos de uso

  1. Atualizar perfil: "Alterar email ou telefone de cliente"
  2. Mudar status: "Marcar pedido como 'enviado'"
  3. Incrementar contador: "Aumentar visualizações de produto"
  4. Corrigir dados: "Ajustar informações incorretas"
  5. Atualização condicional: "Modificar apenas registros específicos"

Quando NÃO usar POSTGRESQL UPDATE

  • Registro pode não existir: Use POSTGRESQL INSERTORUPDATE (upsert)
  • Query complexa: Use POSTGRESQL EXECUTEQUERY para UPDATE com subconsultas
  • Múltiplos registros com lógica: Use EXECUTEQUERY com CASE WHEN
  • Sem condições: NUNCA update sem WHERE (atualizaria tudo!)

Parâmetros Detalhados

config (object, obrigatório)

O que é: Configuração de conexão com PostgreSQL.

Estrutura:

{
  "host": "localhost",
  "port": 5432,
  "database": "nome_database",
  "user": "usuario",
  "password": "senha",
  "ssl": false
}

table (string, obrigatório)

O que é: Nome da tabela onde registros serão atualizados.

values (object, obrigatório)

O que é: Campos e novos valores a serem definidos.

Formato: { "campo1": "novo_valor", "campo2": 456 }

conditions (object, obrigatório)

O que é: Condições WHERE para identificar quais registros atualizar.

Formato: { "id": 123 } ou { "email": "jose@example.com", "ativo": true }

IMPORTANTE: Todas as condições são combinadas com AND

Flow completo para testar:

{
  "name": "Teste PostgreSQL - Update",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "ID Cliente",
        "parameters": {
          "message": "ID do cliente a atualizar:",
          "variable": "clienteId"
        }
      }
    },
    {
      "id": "email_1",
      "type": "email",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Novo Email",
        "parameters": {
          "message": "Novo email:",
          "variable": "novoEmail"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Atualizar Email",
        "parameters": {
          "operation": "update",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "crm",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "table": "clientes",
          "values": {
            "email": "{{novoEmail}}",
            "data_atualizacao": "CURRENT_TIMESTAMP"
          },
          "conditions": {
            "id": "{{clienteId}}"
          },
          "responseVariable": "resultado"
        }
      }
    },
    {
      "id": "condition_1",
      "type": "condition",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Atualizado?",
        "parameters": {
          "conditions": [
            {
              "variable": "resultado.rowCount",
              "operator": "greater_than",
              "value": 0,
              "nextNode": "message_success"
            }
          ],
          "defaultNextNode": "message_notfound"
        }
      }
    },
    {
      "id": "message_success",
      "type": "message",
      "position": { "x": 1100, "y": 50 },
      "data": {
        "label": "Sucesso",
        "parameters": {
          "message": "Email atualizado com sucesso!\n\nNovo email: {{novoEmail}}"
        }
      }
    },
    {
      "id": "message_notfound",
      "type": "message",
      "position": { "x": 1100, "y": 150 },
      "data": {
        "label": "Não Encontrado",
        "parameters": {
          "message": "Cliente com ID {{clienteId}} não foi encontrado."
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "email_1" },
    { "source": "email_1", "target": "postgres_1" },
    { "source": "postgres_1", "target": "condition_1" },
    { "source": "message_success", "target": "end_1" },
    { "source": "message_notfound", "target": "end_1" }
  ]
}

Teste: Registro é atualizado se existir, senão retorna rowCount = 0.

responseVariable (string, opcional)

O que é: Nome da variável para armazenar resultado no contexto.

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim Deve ser "update"
config object Sim Configuração de conexão PostgreSQL
table string Sim Nome da tabela
values object Sim Campos e valores a atualizar
conditions object Sim Condições WHERE (combinadas com AND)
responseVariable string Não Variável para armazenar resultado

Exemplo 1: Atualizar Status de Pedido

Objetivo: Mudar status de pedido para 'enviado' após despacho

JSON para Importar

{
  "name": "PostgreSQL - Atualizar Status Pedido",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Número Pedido",
        "parameters": {
          "message": "Número do pedido despachado:",
          "variable": "pedidoId"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Código Rastreio",
        "parameters": {
          "message": "Código de rastreio:",
          "variable": "codigoRastreio"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Atualizar Pedido",
        "parameters": {
          "operation": "update",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "ecommerce",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "table": "pedidos",
          "values": {
            "status": "enviado",
            "codigo_rastreio": "{{codigoRastreio}}",
            "data_envio": "CURRENT_TIMESTAMP"
          },
          "conditions": {
            "id": "{{pedidoId}}",
            "status": "pendente"
          },
          "responseVariable": "resultado"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Confirmação",
        "parameters": {
          "message": "Pedido {{pedidoId}} atualizado!\n\nStatus: Enviado\nCódigo de Rastreio: {{codigoRastreio}}\n\n{{resultado.rowCount}} pedido(s) atualizado(s)."
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "input_2" },
    { "source": "input_2", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Número do pedido despachado:
Usuário: 1523
Sistema: Código de rastreio:
Usuário: BR123456789BR
Sistema: Pedido 1523 atualizado!

Status: Enviado
Código de Rastreio: BR123456789BR

1 pedido(s) atualizado(s).

Exemplo 2: Atualizar Perfil Completo

Objetivo: Permitir cliente atualizar múltiplos campos do perfil

JSON para Importar

{
  "name": "PostgreSQL - Atualizar Perfil",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Menu",
        "parameters": {
          "message": "Atualização de Perfil\n\nVamos atualizar seus dados."
        }
      }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Novo Nome",
        "parameters": {
          "message": "Novo nome completo:",
          "variable": "novoNome"
        }
      }
    },
    {
      "id": "phone_1",
      "type": "phone",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Novo Telefone",
        "parameters": {
          "message": "Novo telefone:",
          "variable": "novoTelefone"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Nova Cidade",
        "parameters": {
          "message": "Nova cidade:",
          "variable": "novaCidade"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Salvar Alterações",
        "parameters": {
          "operation": "update",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "crm",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "table": "clientes",
          "values": {
            "nome": "{{novoNome}}",
            "telefone": "{{novoTelefone}}",
            "cidade": "{{novaCidade}}",
            "data_atualizacao": "CURRENT_TIMESTAMP"
          },
          "conditions": {
            "id": "{{phone}}"
          },
          "responseVariable": "resultado"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1300, "y": 100 },
      "data": {
        "label": "Sucesso",
        "parameters": {
          "message": "Perfil atualizado com sucesso!\n\nNome: {{novoNome}}\nTelefone: {{novoTelefone}}\nCidade: {{novaCidade}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1500, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "input_1" },
    { "source": "input_1", "target": "phone_1" },
    { "source": "phone_1", "target": "input_2" },
    { "source": "input_2", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_2" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Atualização de Perfil

Vamos atualizar seus dados.
Sistema: Novo nome completo:
Usuário: José Roberto Silva Oliveira
Sistema: Novo telefone:
Usuário: 11999887766
Sistema: Nova cidade:
Usuário: Rio de Janeiro
Sistema: Perfil atualizado com sucesso!

Nome: José Roberto Silva Oliveira
Telefone: 11999887766
Cidade: Rio de Janeiro

Resposta do Node

{
  "updatedRows": [
    {
      "id": 42,
      "nome": "José Roberto Silva Oliveira",
      "email": "jose@example.com",
      "telefone": "11999887766",
      "cidade": "Rio de Janeiro",
      "data_atualizacao": "2025-01-15T15:45:00.000Z",
      "ativo": true
    }
  ],
  "rowCount": 1
}

Boas Práticas

SIM:

  • SEMPRE use conditions (WHERE) para evitar atualizar toda tabela
  • Valide dados antes de atualizar
  • Use CURRENT_TIMESTAMP para campos de auditoria
  • Verifique rowCount para confirmar atualização
  • Capture updatedRows para ver valores finais
  • Use transações para múltiplos updates relacionados

NÃO:

  • NUNCA update sem WHERE (conditions obrigatório!)
  • Não atualize chaves primárias
  • Não ignore rowCount = 0 (registro não existe)
  • Não atualize sem validar formato
  • Não atualize campos calculados (recalcule)
  • Não use UPDATE quando INSERT é necessário

Dicas

💡 RETURNING: PostgreSQL retorna registros atualizados com novos valores

💡 rowCount = 0: Significa que nenhum registro atendeu conditions (não existe)

💡 Múltiplas conditions: Todas são combinadas com AND automaticamente

💡 Timestamps: Use CURRENT_TIMESTAMP para campos de auditoria

💡 Optimistic locking: Adicione version ou updated_at em conditions para evitar conflitos

💡 Partial updates: Atualize apenas campos necessários (não precisa de todos)

💡 Condições complexas: Para OR ou subconsultas, use EXECUTEQUERY

Próximo Node

POSTGRESQL DELETE - Deletar registros → POSTGRESQL INSERT - Inserir registros → POSTGRESQL INSERTORUPDATE - Upsert (Insert ou Update) → POSTGRESQL EXECUTEQUERY - Consultas personalizadas