Expressões e Fórmulas
Expressões permitem criar lógica complexa e transformações de dados avançadas no Flow Builder. Esta página cobre expressões, fórmulas e técnicas avançadas.
Sintaxe de Expressões
Expressões Básicas
Expressões são envolvidas por {{ }} e podem conter JavaScript válido:
// Simples
{{ 2 + 2 }}
// Com variáveis
{{ $vars.price * 1.1 }}
// Booleanas
{{ $vars.age >= 18 }}
// Strings
{{ `Olá, ${$vars.name}!` }}
Expressões em Configurações
{
"url": "{{ $vars.apiUrl }}/users/{{ $trigger.body.userId }}",
"headers": {
"Authorization": "Bearer {{ $vars.token }}",
"X-Request-ID": "{{ $context.executionId }}"
},
"body": {
"processed": "{{ new Date().toISOString() }}",
"data": "{{ JSON.stringify($node.output) }}"
}
}
Operadores Avançados
Operador Ternário
// Sintaxe: condição ? valorVerdadeiro : valorFalso
{{ $vars.isPremium ? 'premium' : 'free' }}
// Aninhado
{{ $vars.score > 90 ? 'A' : $vars.score > 80 ? 'B' : 'C' }}
// Com expressões complexas
{{ $vars.isActive && $vars.verified ? $vars.fullAccess : $vars.limitedAccess }}
Operador Nullish Coalescing (??)
// Retorna o segundo valor apenas se o primeiro for null ou undefined
{{ $vars.customUrl ?? 'https://default.com' }}
// Diferente de || que também considera '', 0, false
{{ $vars.count ?? 10 }} // Se count for 0, retorna 0 (não 10)
{{ $vars.count || 10 }} // Se count for 0, retorna 10
Optional Chaining (?.)
// Evita erros se a propriedade não existir
{{ $node.output.data?.user?.email }}
// Com arrays
{{ $node.output.items?.[0]?.name }}
// Com funções
{{ $vars.customHandler?.() }}
Spread Operator
// Arrays
{{ [...$vars.defaultItems, ...$node.output.newItems] }}
// Objects
{{ { ...$vars.defaults, ...$trigger.body } }}
Funções Personalizadas
Arrow Functions
// Map com arrow function
{{ $node.output.users.map(u => u.email) }}
// Filter com condição
{{ $node.output.products.filter(p => p.price > 100 && p.inStock) }}
// Reduce para soma
{{ $node.output.items.reduce((sum, item) => sum + item.price, 0) }}
Funções Complexas
// Processamento multi-step
{{
$node.output.orders
.filter(o => o.status === 'pending')
.map(o => ({
id: o.id,
total: o.items.reduce((sum, i) => sum + i.price * i.qty, 0),
customer: o.customer.email
}))
.sort((a, b) => b.total - a.total)
}}
Expressões Condicionais
If/Else em Expressões
// Validação de email
{{
$trigger.body.email &&
$trigger.body.email.includes('@') &&
$trigger.body.email.length > 5
}}
// Status baseado em score
{{
$vars.score >= 90 ? 'excellent' :
$vars.score >= 70 ? 'good' :
$vars.score >= 50 ? 'average' : 'poor'
}}
Switch Case Simulado
// Usando objeto como switch
{{
{
'pending': 'Aguardando',
'processing': 'Processando',
'completed': 'Concluído',
'failed': 'Falhou'
}[$vars.status] || 'Desconhecido'
}}
Transformações de Dados
Normalização de Dados
// Normalizar telefone
{{ $trigger.body.phone.replace(/\D/g, '') }}
// Normalizar email
{{ $trigger.body.email.toLowerCase().trim() }}
// Normalizar nome
{{
$trigger.body.name
.trim()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ')
}}
Agregação de Dados
// Somar valores
{{ $node.output.items.reduce((sum, item) => sum + item.value, 0) }}
// Média
{{
$node.output.scores.reduce((sum, s) => sum + s, 0) /
$node.output.scores.length
}}
// Agrupar por categoria
{{
$node.output.products.reduce((acc, p) => {
acc[p.category] = acc[p.category] || [];
acc[p.category].push(p);
return acc;
}, {})
}}
Filtragem e Ordenação
// Filtrar e ordenar
{{
$node.output.users
.filter(u => u.active && u.verified)
.sort((a, b) => b.score - a.score)
.slice(0, 10)
}}
// Remover duplicatas
{{ [...new Set($node.output.emails)] }}
// Filtrar valores únicos por propriedade
{{
$node.output.items
.filter((item, index, self) =>
self.findIndex(i => i.id === item.id) === index
)
}}
Manipulação de Strings
Templates Complexos
// Template de email
{{ `
Olá ${$vars.userName},
Seu pedido #${$trigger.body.orderId} foi confirmado.
Total: R$ ${$trigger.body.total.toFixed(2)}
Previsão de entrega: ${new Date($trigger.body.deliveryDate).toLocaleDateString('pt-BR')}
Obrigado pela preferência!
`.trim() }}
Regex
// Validar formato
{{ /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$/.test($vars.email) }}
// Extrair números
{{ $vars.text.match(/\d+/g) }}
// Substituir múltiplos espaços
{{ $vars.text.replace(/\s+/g, ' ') }}
// Extrair domínio de email
{{ $vars.email.match(/@(.+)$/)?.[1] }}
Formatação
// CPF
{{
$vars.cpf.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
}}
// Telefone
{{
$vars.phone.replace(/(\d{2})(\d{5})(\d{4})/, '($1) $2-$3')
}}
// CEP
{{
$vars.cep.replace(/(\d{5})(\d{3})/, '$1-$2')
}}
Manipulação de Datas
Cálculos de Data
// Adicionar dias
{{
new Date(Date.now() + (7 * 24 * 60 * 60 * 1000)).toISOString()
}}
// Diferença em dias
{{
Math.floor(
(new Date($vars.endDate) - new Date($vars.startDate)) /
(1000 * 60 * 60 * 24)
)
}}
// Primeiro dia do mês
{{
new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString()
}}
// Último dia do mês
{{
new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).toISOString()
}}
Formatação de Data
// Brasileiro
{{
new Date($vars.date).toLocaleDateString('pt-BR', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
})
}}
// Data e hora completa
{{
new Date($vars.date).toLocaleString('pt-BR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
}}
// Relativo
{{
(() => {
const diff = Date.now() - new Date($vars.date).getTime();
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) return 'agora';
if (minutes < 60) return `${minutes}min atrás`;
if (hours < 24) return `${hours}h atrás`;
return `${days}d atrás`;
})()
}}
Manipulação de Arrays
Métodos Avançados
// Every - todos atendem a condição
{{ $node.output.users.every(u => u.age >= 18) }}
// Some - pelo menos um atende a condição
{{ $node.output.permissions.some(p => p === 'admin') }}
// Flat - achatar arrays aninhados
{{ $node.output.nestedArray.flat(2) }}
// FlatMap - map + flat
{{ $node.output.users.flatMap(u => u.emails) }}
Transformações Complexas
// Criar lookup object
{{
$node.output.users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {})
}}
// Pivot de dados
{{
$node.output.sales.reduce((acc, sale) => {
const month = new Date(sale.date).getMonth();
acc[month] = (acc[month] || 0) + sale.amount;
return acc;
}, {})
}}
Manipulação de Objetos
Transformações
// Selecionar campos específicos
{{
Object.fromEntries(
Object.entries($node.output.user)
.filter(([key]) => ['id', 'name', 'email'].includes(key))
)
}}
// Renomear chaves
{{
Object.fromEntries(
Object.entries($node.output.data)
.map(([key, value]) => [key.toLowerCase(), value])
)
}}
// Merge profundo
{{
(() => {
const merge = (target, source) => {
for (const key in source) {
if (source[key] instanceof Object && key in target) {
Object.assign(source[key], merge(target[key], source[key]));
}
}
return Object.assign(target || {}, source);
};
return merge($vars.defaults, $trigger.body);
})()
}}
Validações Avançadas
Validação de Schema
// Validar estrutura de objeto
{{
(() => {
const data = $trigger.body;
return (
typeof data.name === 'string' &&
typeof data.email === 'string' &&
typeof data.age === 'number' &&
data.age > 0 &&
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)
);
})()
}}
Validação de Lista
// Validar todos os itens
{{
$node.output.items.length > 0 &&
$node.output.items.every(item =>
item.id &&
item.price > 0 &&
item.quantity > 0
)
}}
Performance e Otimização
Evitar Cálculos Redundantes
❌ Não otimizado:
{{ $node.output.items.length > 0 ? $node.output.items.length : 0 }}
✅ Otimizado:
{{ $node.output.items.length || 0 }}
Cache de Valores
Use variáveis intermediárias para valores reutilizados:
// Armazene em variável para reutilizar
{{
(() => {
const items = $node.output.items.filter(i => i.active);
return {
count: items.length,
total: items.reduce((sum, i) => sum + i.price, 0),
items: items
};
})()
}}
Exemplos Práticos Completos
Exemplo 1: Formatador de Endereço
{{
(() => {
const addr = $trigger.body.address;
return `${addr.street}, ${addr.number}${addr.complement ? ' - ' + addr.complement : ''}
${addr.neighborhood} - ${addr.city}/${addr.state}
CEP: ${addr.zipCode.replace(/(\d{5})(\d{3})/, '$1-$2')}`;
})()
}}
Exemplo 2: Calculadora de Carrinho
{{
(() => {
const items = $node.output.cartItems;
const subtotal = items.reduce((sum, i) => sum + (i.price * i.quantity), 0);
const discount = $vars.discountPercent ? subtotal * ($vars.discountPercent / 100) : 0;
const shipping = subtotal > 100 ? 0 : 15.00;
const total = subtotal - discount + shipping;
return {
subtotal: subtotal.toFixed(2),
discount: discount.toFixed(2),
shipping: shipping.toFixed(2),
total: total.toFixed(2),
itemCount: items.reduce((sum, i) => sum + i.quantity, 0)
};
})()
}}
Exemplo 3: Gerador de Relatório
{{
(() => {
const sales = $node.output.salesData;
const byCategory = sales.reduce((acc, sale) => {
acc[sale.category] = (acc[sale.category] || 0) + sale.amount;
return acc;
}, {});
const topCategory = Object.entries(byCategory)
.sort(([,a], [,b]) => b - a)[0];
return {
totalSales: sales.length,
totalRevenue: sales.reduce((sum, s) => sum + s.amount, 0).toFixed(2),
averageTicket: (sales.reduce((sum, s) => sum + s.amount, 0) / sales.length).toFixed(2),
topCategory: topCategory[0],
topCategoryRevenue: topCategory[1].toFixed(2),
categories: byCategory
};
})()
}}
Tratamento de Erros em Expressões
Try-Catch
{{
(() => {
try {
return JSON.parse($trigger.body.data);
} catch (e) {
return { error: 'Invalid JSON', message: e.message };
}
})()
}}
Validação Defensiva
{{
$node.output?.data?.items?.length > 0
? $node.output.data.items[0].value
: null
}}
Boas Práticas
1. Mantenha Expressões Legíveis
❌ Difícil de ler:
{{$node.output.items.filter(i=>i.price>100&&i.stock>0).map(i=>({id:i.id,total:i.price*1.1}))}}
✅ Legível:
{{
$node.output.items
.filter(i => i.price > 100 && i.stock > 0)
.map(i => ({
id: i.id,
total: i.price * 1.1
}))
}}
2. Use IIFE para Lógica Complexa
{{
(() => {
// Lógica multi-step clara
const data = $node.output.rawData;
const filtered = data.filter(/* ... */);
const transformed = filtered.map(/* ... */);
return transformed;
})()
}}
3. Documente Expressões Complexas
Use nós de comentário ou descrições para explicar expressões não óbvias.
Próximos Passos
- Referência de Nós: Veja todos os nós disponíveis
- Primeiro Flow: Crie seu primeiro flow
- Tutoriais: Aprenda com exemplos práticos