Pular para conteúdo

DYNAMODB_QUERY - Buscar Múltiplos Itens por Partition Key

O que é este Node?

O DYNAMODB_QUERY é o node responsável por buscar múltiplos itens de uma tabela DynamoDB usando a Partition Key, opcionalmente filtrando pela Sort Key e outros atributos.

Por que este Node existe?

Query é a operação mais eficiente para buscar conjuntos de dados relacionados no DynamoDB. O DYNAMODB_QUERY existe para:

  1. Performance: Busca apenas na partição específica (não escaneia a tabela inteira)
  2. Relacionamentos: Recupera todos os itens de um usuário, pedidos de uma data, etc.
  3. Ordenação: Retorna itens ordenados pela Sort Key automaticamente
  4. Filtros: Permite condições adicionais sem carregar dados desnecessários

Como funciona internamente?

Quando o DYNAMODB_QUERY é executado, o sistema:

  1. Autentica: Valida as credenciais AWS
  2. Monta Expressão: Cria KeyConditionExpression com Partition Key (obrigatório) e Sort Key (opcional)
  3. Localiza Partição: Vai direto para a partição específica (não escaneia toda tabela)
  4. Filtra: Aplica Sort Key e FilterExpression se fornecidos
  5. Ordena: Retorna itens ordenados pela Sort Key (crescente por padrão)
  6. Limita: Aplica limite de itens se especificado
  7. Retorna: Array de itens encontrados + contagem

Código interno (aws-executors.service.ts:313-324):

case 'query':
  const queryResult = await dynamodb.query({
    TableName: data.tableName,
    KeyConditionExpression: data.keyConditionExpression,
    ExpressionAttributeValues: data.expressionAttributeValues,
    Limit: data.limit,
  }).promise();
  return {
    success: true,
    items: queryResult.Items,
    count: queryResult.Count,
  };

Quando você DEVE usar este Node?

Use DYNAMODB_QUERY sempre que precisar de buscar múltiplos itens relacionados:

Casos de uso

  1. Histórico do usuário: "Buscar todos os pedidos de um cliente específico"
  2. Timeline: "Listar todas as mensagens de um chat nos últimos 7 dias"
  3. Ranking: "Top 10 produtos mais vendidos em uma categoria"
  4. Logs filtrados: "Buscar erros de uma aplicação em determinado período"

Quando NÃO usar DYNAMODB_QUERY

  • Buscar item único por chave: Use DYNAMODB_GET ao invés (mais eficiente)
  • Buscar sem Partition Key: Use DYNAMODB_SCAN (porém é lento e caro)
  • Buscar em múltiplas partições: Use DYNAMODB_SCAN ou múltiplos Query
  • Buscar por atributo não-chave sem índice: Use DYNAMODB_SCAN

Parâmetros Detalhados

accessKeyId (string, obrigatório)

O que é: Chave de acesso da AWS para autenticação.

Padrão: Nenhum (sempre obrigatório)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Access Key",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 100 },
      "data": {
        "label": "User ID",
        "parameters": {
          "message": "Digite seu ID para buscar pedidos:",
          "variableName": "user_id"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 400, "y": 100 },
      "data": {
        "label": "Buscar Pedidos",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Pedidos",
          "keyConditionExpression": "userId = :uid",
          "expressionAttributeValues": {
            ":uid": "{{user_id}}"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 550, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Encontrados {{dynamodb_1.count}} pedidos"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite um ID de usuário. Verá quantos pedidos esse usuário tem.

secretAccessKey (string, obrigatório)

O que é: Chave secreta da AWS.

Padrão: Nenhum (sempre obrigatório)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Secret Key",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 100 },
      "data": {
        "label": "Categoria",
        "parameters": {
          "message": "Digite a categoria do produto:",
          "variableName": "category"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 400, "y": 100 },
      "data": {
        "label": "Buscar Produtos",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "sa-east-1",
          "operation": "query",
          "tableName": "Produtos",
          "keyConditionExpression": "categoria = :cat",
          "expressionAttributeValues": {
            ":cat": "{{category}}"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 550, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "{{dynamodb_1.count}} produtos na categoria {{category}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite nome de categoria. Verá quantos produtos existem nela.

region (string, obrigatório)

O que é: Região AWS da tabela DynamoDB.

Padrão: Nenhum (sempre obrigatório)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Region",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 150 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 150 },
      "data": {
        "label": "Store ID",
        "parameters": {
          "message": "Digite o ID da loja:",
          "variableName": "store_id"
        }
      }
    },
    {
      "id": "switch_1",
      "type": "switch",
      "position": { "x": 400, "y": 150 },
      "data": {
        "label": "Escolher Região",
        "parameters": {
          "message": "Região da loja?\n1️⃣ US\n2️⃣ Brasil",
          "cases": [
            { "value": "1", "label": "US" },
            { "value": "2", "label": "BR" }
          ]
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 100 },
      "data": {
        "label": "Query US",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Vendas",
          "keyConditionExpression": "storeId = :sid",
          "expressionAttributeValues": {
            ":sid": "{{store_id}}"
          }
        }
      }
    },
    {
      "id": "dynamodb_2",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 200 },
      "data": {
        "label": "Query BR",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "sa-east-1",
          "operation": "query",
          "tableName": "Vendas",
          "keyConditionExpression": "storeId = :sid",
          "expressionAttributeValues": {
            ":sid": "{{store_id}}"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 150 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Vendas encontradas na região selecionada"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 850, "y": 150 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "switch_1" },
    { "source": "switch_1", "target": "dynamodb_1", "label": "1" },
    { "source": "switch_1", "target": "dynamodb_2", "label": "2" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "dynamodb_2", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Escolha região. Query busca apenas naquela região específica.

tableName (string, obrigatório)

O que é: Nome da tabela DynamoDB onde buscar.

Padrão: Nenhum (sempre obrigatório)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Table Name",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 100 },
      "data": {
        "label": "Tabela",
        "parameters": {
          "message": "Nome da tabela:",
          "variableName": "table_name"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 400, "y": 100 },
      "data": {
        "label": "Partition Key",
        "parameters": {
          "message": "Valor da Partition Key:",
          "variableName": "pk_value"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 100 },
      "data": {
        "label": "Query Dinâmica",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "{{table_name}}",
          "keyConditionExpression": "pk = :pkval",
          "expressionAttributeValues": {
            ":pkval": "{{pk_value}}"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Query executada em {{table_name}}: {{dynamodb_1.count}} itens"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 850, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "input_2" },
    { "source": "input_2", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite nome de tabela e valor. Se tabela não existir, erro "ResourceNotFoundException".

keyConditionExpression (string, obrigatório)

O que é: Expressão que define a busca. DEVE incluir Partition Key. Pode incluir Sort Key.

Padrão: Nenhum (sempre obrigatório)

Sintaxe: - Partition Key apenas: userId = :uid - Com Sort Key (igual): userId = :uid AND timestamp = :ts - Com Sort Key (range): userId = :uid AND timestamp BETWEEN :start AND :end - Operadores Sort Key: =, <, <=, >, >=, BETWEEN, begins_with()

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Key Condition",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 200 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 200 },
      "data": {
        "label": "User ID",
        "parameters": {
          "message": "Digite seu ID:",
          "variableName": "user_id"
        }
      }
    },
    {
      "id": "switch_1",
      "type": "switch",
      "position": { "x": 400, "y": 200 },
      "data": {
        "label": "Filtro",
        "parameters": {
          "message": "Buscar pedidos:\n1️⃣ Todos\n2️⃣ Últimos 7 dias\n3️⃣ 2025",
          "cases": [
            { "value": "1", "label": "Todos" },
            { "value": "2", "label": "7 dias" },
            { "value": "3", "label": "2025" }
          ]
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 150 },
      "data": {
        "label": "Query Todos",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Pedidos",
          "keyConditionExpression": "userId = :uid",
          "expressionAttributeValues": {
            ":uid": "{{user_id}}"
          }
        }
      }
    },
    {
      "id": "dynamodb_2",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 250 },
      "data": {
        "label": "Query Recentes",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Pedidos",
          "keyConditionExpression": "userId = :uid AND createdAt > :weekAgo",
          "expressionAttributeValues": {
            ":uid": "{{user_id}}",
            ":weekAgo": "2025-10-05"
          }
        }
      }
    },
    {
      "id": "dynamodb_3",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 350 },
      "data": {
        "label": "Query 2025",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Pedidos",
          "keyConditionExpression": "userId = :uid AND begins_with(createdAt, :year)",
          "expressionAttributeValues": {
            ":uid": "{{user_id}}",
            ":year": "2025"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 250 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Pedidos encontrados conforme filtro selecionado"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 850, "y": 250 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "switch_1" },
    { "source": "switch_1", "target": "dynamodb_1", "label": "1" },
    { "source": "switch_1", "target": "dynamodb_2", "label": "2" },
    { "source": "switch_1", "target": "dynamodb_3", "label": "3" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "dynamodb_2", "target": "message_1" },
    { "source": "dynamodb_3", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Escolha filtro. Cada opção usa KeyConditionExpression diferente.

expressionAttributeValues (object, obrigatório)

O que é: Valores das variáveis usadas na KeyConditionExpression. Formato: { ":variavel": "valor" }

Padrão: Nenhum (sempre obrigatório quando há placeholders)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Expression Attribute Values",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 150 },
      "data": { "label": "Início" }
    },
    {
      "id": "email_1",
      "type": "email",
      "position": { "x": 250, "y": 150 },
      "data": {
        "label": "Email",
        "parameters": {
          "message": "Digite seu email:",
          "variableName": "user_email"
        }
      }
    },
    {
      "id": "date_1",
      "type": "date",
      "position": { "x": 400, "y": 150 },
      "data": {
        "label": "Data Início",
        "parameters": {
          "message": "Data inicial (DD/MM/AAAA):",
          "variableName": "start_date"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 150 },
      "data": {
        "label": "Buscar Atividades",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Atividades",
          "keyConditionExpression": "email = :e AND dataAtividade >= :d",
          "expressionAttributeValues": {
            ":e": "{{user_email}}",
            ":d": "{{start_date}}"
          }
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 150 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "{{dynamodb_1.count}} atividades desde {{start_date}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 850, "y": 150 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "email_1" },
    { "source": "email_1", "target": "date_1" },
    { "source": "date_1", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite email e data. Os valores são substituídos nos placeholders da expressão.

limit (number, opcional)

O que é: Número máximo de itens a retornar. Útil para paginação e controle de custos.

Padrão: Sem limite (retorna todos até 1MB de dados)

Flow completo para testar:

{
  "name": "Teste DynamoDB Query - Limit",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 250, "y": 100 },
      "data": {
        "label": "User ID",
        "parameters": {
          "message": "Digite seu ID:",
          "variableName": "user_id"
        }
      }
    },
    {
      "id": "number_1",
      "type": "number",
      "position": { "x": 400, "y": 100 },
      "data": {
        "label": "Limite",
        "parameters": {
          "message": "Quantos itens mostrar? (1-100)",
          "variableName": "item_limit"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 100 },
      "data": {
        "label": "Query com Limite",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "Historico",
          "keyConditionExpression": "userId = :uid",
          "expressionAttributeValues": {
            ":uid": "{{user_id}}"
          },
          "limit": "{{item_limit}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Mostrando {{dynamodb_1.count}} de seus registros (limite: {{item_limit}})"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 850, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "number_1" },
    { "source": "number_1", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite um número. Apenas aquela quantidade de itens será retornada.

Parâmetros

Campo Tipo Obrigatório Descrição
accessKeyId string Sim Chave de acesso AWS
secretAccessKey string Sim Chave secreta AWS
region string Sim Região AWS (ex: us-east-1)
operation string Sim Tipo de operação (sempre "query")
tableName string Sim Nome da tabela DynamoDB
keyConditionExpression string Sim Expressão de busca (DEVE ter Partition Key)
expressionAttributeValues object Sim Valores dos placeholders da expressão
limit number Não Máximo de itens a retornar

Exemplo 1: Histórico de Pedidos do Cliente

Objetivo: Demonstrar busca de todos os pedidos de um cliente específico, ordenados por data.

JSON para Importar

{
  "name": "Histórico de Pedidos - Query",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 200 },
      "data": { "label": "Início" }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 250, "y": 200 },
      "data": {
        "label": "Boas-vindas",
        "parameters": {
          "message": "📦 Consulta de Pedidos\n\nVamos buscar seu histórico."
        }
      }
    },
    {
      "id": "email_1",
      "type": "email",
      "position": { "x": 400, "y": 200 },
      "data": {
        "label": "Email",
        "parameters": {
          "message": "Digite seu email:",
          "variableName": "customer_email"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 550, "y": 200 },
      "data": {
        "label": "Buscar Pedidos",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "sa-east-1",
          "operation": "query",
          "tableName": "Pedidos",
          "keyConditionExpression": "customerEmail = :email",
          "expressionAttributeValues": {
            ":email": "{{customer_email}}"
          },
          "limit": 10
        }
      }
    },
    {
      "id": "condition_1",
      "type": "condition",
      "position": { "x": 700, "y": 200 },
      "data": {
        "label": "Tem Pedidos?",
        "parameters": {
          "variable": "{{dynamodb_1.count}}",
          "operator": ">",
          "value": "0"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 850, "y": 150 },
      "data": {
        "label": "Mostrar Pedidos",
        "parameters": {
          "message": "📋 Seus Pedidos (últimos 10):\n\nTotal: {{dynamodb_1.count}} pedidos\n\n{{#each dynamodb_1.items}}\n🆔 {{this.pedidoId}}\n📅 {{this.data}}\n💰 R$ {{this.valorTotal}}\n📊 Status: {{this.status}}\n---\n{{/each}}"
        }
      }
    },
    {
      "id": "message_3",
      "type": "message",
      "position": { "x": 850, "y": 250 },
      "data": {
        "label": "Sem Pedidos",
        "parameters": {
          "message": "📭 Você ainda não tem pedidos.\n\nQue tal fazer seu primeiro pedido?"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1000, "y": 200 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "email_1" },
    { "source": "email_1", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "condition_1" },
    { "source": "condition_1", "target": "message_2", "label": "true" },
    { "source": "condition_1", "target": "message_3", "label": "false" },
    { "source": "message_2", "target": "end_1" },
    { "source": "message_3", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📦 Consulta de Pedidos

Vamos buscar seu histórico.

Sistema: Digite seu email:
Usuário: jose@example.com

Sistema: 📋 Seus Pedidos (últimos 10):

Total: 3 pedidos

🆔 PED-001
📅 2025-10-01
💰 R$ 299.90
📊 Status: entregue
---
🆔 PED-002
📅 2025-10-05
💰 R$ 1499.00
📊 Status: em trânsito
---
🆔 PED-003
📅 2025-10-10
💰 R$ 89.90
📊 Status: processando
---

Exemplo 2: Mensagens de Chat por Período

Objetivo: Demonstrar Query com Sort Key range (BETWEEN) para buscar mensagens em intervalo de datas.

JSON para Importar

{
  "name": "Mensagens de Chat por Período - Query BETWEEN",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 250 },
      "data": { "label": "Início" }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 250, "y": 250 },
      "data": {
        "label": "Iniciar",
        "parameters": {
          "message": "💬 Histórico de Chat\n\nBuscar mensagens por período."
        }
      }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 400, "y": 250 },
      "data": {
        "label": "Chat ID",
        "parameters": {
          "message": "Digite o ID do chat:",
          "variableName": "chat_id"
        }
      }
    },
    {
      "id": "date_1",
      "type": "date",
      "position": { "x": 550, "y": 200 },
      "data": {
        "label": "Data Início",
        "parameters": {
          "message": "Data inicial (DD/MM/AAAA):",
          "variableName": "start_date"
        }
      }
    },
    {
      "id": "date_2",
      "type": "date",
      "position": { "x": 550, "y": 300 },
      "data": {
        "label": "Data Fim",
        "parameters": {
          "message": "Data final (DD/MM/AAAA):",
          "variableName": "end_date"
        }
      }
    },
    {
      "id": "dynamodb_1",
      "type": "dynamodb_query",
      "position": { "x": 700, "y": 250 },
      "data": {
        "label": "Query Mensagens",
        "parameters": {
          "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
          "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
          "region": "us-east-1",
          "operation": "query",
          "tableName": "ChatMensagens",
          "keyConditionExpression": "chatId = :cid AND timestamp BETWEEN :start AND :end",
          "expressionAttributeValues": {
            ":cid": "{{chat_id}}",
            ":start": "{{start_date}}T00:00:00Z",
            ":end": "{{end_date}}T23:59:59Z"
          }
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 850, "y": 250 },
      "data": {
        "label": "Mostrar Resultado",
        "parameters": {
          "message": "💬 Mensagens Encontradas: {{dynamodb_1.count}}\n\n📅 Período: {{start_date}} a {{end_date}}\n\n{{#each dynamodb_1.items}}\n⏰ {{this.timestamp}}\n👤 {{this.remetente}}: {{this.mensagem}}\n---\n{{/each}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1000, "y": 250 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "input_1" },
    { "source": "input_1", "target": "date_1" },
    { "source": "date_1", "target": "date_2" },
    { "source": "date_2", "target": "dynamodb_1" },
    { "source": "dynamodb_1", "target": "message_2" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 💬 Histórico de Chat

Buscar mensagens por período.

Sistema: Digite o ID do chat:
Usuário: chat_12345

Sistema: Data inicial (DD/MM/AAAA):
Usuário: 01/10/2025

Sistema: Data final (DD/MM/AAAA):
Usuário: 10/10/2025

Sistema: 💬 Mensagens Encontradas: 15

📅 Período: 01/10/2025 a 10/10/2025

⏰ 2025-10-01T10:30:00Z
👤 João: Olá, tudo bem?
---
⏰ 2025-10-01T10:31:15Z
👤 Maria: Oi! Tudo sim, e você?
---
⏰ 2025-10-05T14:22:00Z
👤 João: Quando podemos nos reunir?
---

Resposta do Node

{
  "success": true,
  "items": [
    {
      "userId": "user123",
      "pedidoId": "PED-001",
      "data": "2025-10-01",
      "valorTotal": 299.90,
      "status": "entregue"
    },
    {
      "userId": "user123",
      "pedidoId": "PED-002",
      "data": "2025-10-05",
      "valorTotal": 1499.00,
      "status": "em trânsito"
    }
  ],
  "count": 2
}

Diferença: Query vs Scan

QUERY (Recomendado)

  • Performance: Rápido - busca apenas em 1 partição
  • Custo: Baixo - paga apenas pelos itens lidos
  • Requisito: DEVE ter Partition Key na condição
  • Ordenação: Automática pela Sort Key
  • Uso: Quando você sabe a Partition Key

SCAN (Evitar quando possível)

  • Performance: Lento - lê TODA a tabela
  • Custo: Alto - paga por TODOS os itens escaneados
  • Requisito: Nenhum - busca em toda tabela
  • Ordenação: Nenhuma garantia
  • Uso: Quando NÃO sabe a Partition Key ou precisa de todos os dados

Exemplo de custo: - Tabela com 1 milhão de itens - Query: Lê 10 itens da partição = $0.000001 - Scan: Lê 1 milhão de itens = $0.10 (100.000x mais caro!)

Boas Práticas

SIM:

  • SEMPRE use Query ao invés de Scan quando souber a Partition Key
  • Use limit para controlar quantidade de dados retornados
  • Crie GSI (Global Secondary Index) para queries em outros atributos
  • Use begins_with() para buscar prefixos (ex: ano "2025")
  • Combine Partition Key + Sort Key range para buscas precisas
  • Ordene resultados aproveitando a Sort Key

NÃO:

  • Fazer Query sem Partition Key (use Scan ou crie GSI)
  • Buscar em múltiplas partições com um Query (faça múltiplos Queries)
  • Retornar milhares de itens sem paginação (use limit)
  • Usar FilterExpression quando Sort Key pode fazer o filtro (menos eficiente)
  • Assumir que Query retorna TODOS os itens (DynamoDB limita a 1MB por request)

Dicas

💡 Dica 1: Query retorna itens ordenados pela Sort Key. Use isso ao seu favor: timestamps como Sort Key dão timeline automática!

💡 Dica 2: begins_with() é perfeito para hierarquias: begins_with(categoria, "Eletrônicos/") encontra "Eletrônicos/TV", "Eletrônicos/Notebook", etc.

💡 Dica 3: Query pode retornar até 1MB de dados por request. Para mais, implemente paginação usando LastEvaluatedKey.

💡 Dica 4: Se você faz Query frequente em atributo não-chave, crie GSI (Global Secondary Index). Transforma atributo comum em Partition Key para queries rápidas.

💡 Dica 5: Use ScanIndexForward: false (no código) para inverter ordem da Sort Key (do mais recente para o mais antigo).

Próximo Node

DYNAMODB_GET - Buscar item único por chave → DYNAMODB_SCAN - Escanear tabela inteira com filtros → DYNAMODB_UPDATE - Atualizar campos específicos