Tabelas guardam coisas. Produtos reais também precisam guardar conexões: quem indicou quem, qual aluno concluiu qual aula, qual profissional atende qual região, quais pessoas pertencem a uma comunidade e como uma compra chegou até uma campanha.
Quando essas conexões respondem perguntas importantes, um grafo deixa de ser uma escolha exótica e vira uma forma direta de representar o negócio. SurrealDB permite combinar registros, documentos e relações no mesmo banco, usando arestas que também carregam dados.
O que é um grafo no banco de dados?
Um grafo é formado por nós e arestas. Nós representam entidades — pessoa, curso, produto, cidade. Arestas representam relações — matriculou-se, indicou, comprou, atende — e podem guardar propriedades como data, papel, origem e status.
No SurrealDB, a relação é criada com RELATE e percorrida com setas:
RELATE profile:ana->enrolled_in->course:surrealdb
SET status = 'active',
source = 'pix',
enrolled_at = time::now();
SELECT ->enrolled_in->course.{ title, level }
FROM profile:ana;O curso e o perfil continuam sendo registros normais. enrolled_in é uma relação com significado e histórico próprios.
Quando usar relação de grafo ou record link?
Nem toda referência precisa virar aresta.
| Situação | Modelo preferível |
|---|---|
| pedido pertence a um cliente | campo record<cliente> |
| usuário segue outro usuário | relação follows |
| artigo possui um autor principal | record link |
| aluno se matricula e a matrícula tem status/data | relação enrolled_in |
| endereço atual de entrega | objeto ou record link |
| indicação precisa guardar campanha e recompensa | relação referred |
Use record link quando a conexão é simples e unilateral. Use relation table quando o vínculo tem propriedades, regras, unicidade, histórico ou precisa ser percorrido em várias direções.
Cenário 1: comunidade e rede de indicações
Uma comunidade brasileira pode recomendar conexões, premiar indicações e mostrar conteúdo de pessoas seguidas. O modelo base inclui perfis e duas relações.
DEFINE TABLE profile SCHEMAFULL;
DEFINE FIELD name ON profile TYPE string;
DEFINE FIELD city ON profile TYPE option<string>;
DEFINE FIELD joined_at ON profile TYPE datetime DEFAULT time::now();
DEFINE TABLE follows SCHEMAFULL
TYPE RELATION IN profile OUT profile;
DEFINE FIELD since ON follows TYPE datetime DEFAULT time::now();
DEFINE INDEX follows_unique ON follows FIELDS in, out UNIQUE;
DEFINE TABLE referred SCHEMAFULL
TYPE RELATION IN profile OUT profile;
DEFINE FIELD campaign ON referred TYPE option<string>;
DEFINE FIELD converted_at ON referred TYPE option<datetime>;
DEFINE FIELD reward_centavos ON referred TYPE int DEFAULT 0;
DEFINE INDEX referral_unique ON referred FIELDS in, out UNIQUE;Uma sugestão “pessoas que você talvez conheça” pode percorrer dois saltos: pessoas seguidas por quem Ana segue, excluindo a própria Ana e quem ela já segue.
O tutorial oficial de grafos sociais mostra como seguidores, comentários, clubes e rankings podem coexistir em um modelo desse tipo. A adaptação brasileira não está em traduzir nomes; está em escolher conexões que geram valor local, como indicação, região, turma, parceiro ou revendedor.
[ CONTEÚDO_INTEGRAL_DISPONÍVEL ]
Continuar: grafos para educação, marketplace e marketing CLIQUE PARA DESBLOQUEAR A LEITURA
Construindo aplicações robustas com arquitetura de alto nível e infraestrutura otimizada na edge do Cloudflare Workers com SurrealDB.
Segurança de dados e conformidade com privacidade desde o primeiro dia de código com tratamento de estados e sessões resilientes.
Métricas de performance para monitorar a experiência do usuário e otimizar custos operacionais em produção com dashboards estruturados.
Construindo aplicações robustas com arquitetura de alto nível e infraestrutura otimizada na edge do Cloudflare Workers com SurrealDB.
Segurança de dados e conformidade com privacidade desde o primeiro dia de código com tratamento de estados e sessões resilientes.
Métricas de performance para monitorar a experiência do usuário e otimizar custos operacionais em produção com dashboards estruturados.
Cenário 2: educação e jornada do aluno
Em uma plataforma de cursos, uma tabela de matrículas resolve o básico. O grafo se torna mais interessante quando o produto precisa conectar pré-requisitos, trilhas, habilidades e progresso.
DEFINE TABLE course SCHEMAFULL;
DEFINE FIELD title ON course TYPE string;
DEFINE FIELD level ON course TYPE string
ASSERT $value IN ['beginner', 'intermediate', 'advanced'];
DEFINE TABLE skill SCHEMAFULL;
DEFINE FIELD name ON skill TYPE string;
DEFINE TABLE teaches SCHEMAFULL
TYPE RELATION IN course OUT skill;
DEFINE FIELD weight ON teaches TYPE decimal
ASSERT $value > 0dec AND $value <= 1dec;
DEFINE TABLE requires SCHEMAFULL
TYPE RELATION IN course OUT course;
DEFINE FIELD mandatory ON requires TYPE bool DEFAULT true;
DEFINE TABLE enrolled_in SCHEMAFULL
TYPE RELATION IN profile OUT course;
DEFINE FIELD progress ON enrolled_in TYPE decimal DEFAULT 0dec
ASSERT $value >= 0dec AND $value <= 1dec;
DEFINE FIELD status ON enrolled_in TYPE string
ASSERT $value IN ['active', 'completed', 'cancelled'];Agora o produto pode perguntar: quais habilidades este curso ensina? Quais cursos exigem um curso anterior? Qual é o próximo conteúdo coerente com aquilo que o aluno concluiu?
Recomendação não precisa começar com IA. Uma travessia bem modelada costuma ser mais explicável e barata que enviar todo o catálogo para um modelo.
Cenário 3: marketplace de serviços locais
Um marketplace conecta prestadores, serviços, cidades, avaliações e disponibilidade. A pergunta de busca não é apenas “qual profissional tem esta categoria?”, mas “quem atende minha região, oferece o serviço, está disponível e possui sinais de confiança?”.
Um modelo híbrido funciona bem:
provider,serviceecitycomo nós;offerspara preço inicial, duração e modalidade;servespara raio ou área atendida;reviewedpara nota, comentário e pedido verificado;- agenda como registros temporais, quando travessia de grafo não acrescentar valor.
DEFINE TABLE offers SCHEMAFULL
TYPE RELATION IN provider OUT service;
DEFINE FIELD price_from_centavos ON offers TYPE int
ASSERT $value >= 0;
DEFINE FIELD mode ON offers TYPE string
ASSERT $value IN ['online', 'presencial', 'hibrido'];
DEFINE INDEX offer_unique ON offers FIELDS in, out UNIQUE;
DEFINE TABLE serves SCHEMAFULL
TYPE RELATION IN provider OUT city;
DEFINE FIELD radius_km ON serves TYPE option<decimal>;
DEFINE TABLE reviewed SCHEMAFULL
TYPE RELATION IN customer OUT provider;
DEFINE FIELD rating ON reviewed TYPE int
ASSERT $value >= 1 AND $value <= 5;
DEFINE FIELD comment ON reviewed TYPE option<string>;
DEFINE FIELD verified_order ON reviewed TYPE record<order>;Não guarde dinheiro em float. Centavos inteiros ou um tipo decimal cuidadosamente tratado são escolhas mais seguras. Também não deixe uma avaliação nascer apenas com IDs enviados pelo navegador: confirme que o pedido pertence ao cliente e foi concluído.
Cenário 4: atribuição de marketing sem perder a jornada
Produtos brasileiros dependem de WhatsApp, indicação, anúncios e conteúdo orgânico. Uma conversão raramente tem um único ponto de contato.
Um grafo pode ligar visitante, sessão, campanha, página, lead e compra. A relação carrega horário, canal, identificador de clique e posição na jornada. Isso permite consultar caminhos sem esmagar tudo num campo utm_source do cadastro final.
O cuidado é proporcional ao valor desses dados. Identificadores de publicidade, telefone e histórico de navegação podem se tornar dados pessoais. Defina retenção, acesso e finalidade; não colete “porque talvez um dia seja útil”.
Unicidade e idempotência pertencem às arestas
Seguir alguém duas vezes, dar dois likes iguais ou criar duas matrículas ativas pode corromper métricas e cobrar duas vezes uma automação. Use índice único nas relações em que apenas um vínculo pode existir.
Quando múltiplas relações são legítimas — várias compras do mesmo produto, por exemplo — use um ID idempotente derivado do evento ou uma chave única do provedor de pagamento. O modelo precisa distinguir repetição acidental de recorrência real.
Grafo não dispensa índice nem limite
Uma travessia elegante ainda pode ser cara. Antes de colocar uma consulta em produção:
- limite profundidade e quantidade de resultados;
- filtre cedo por status, tenant ou período;
- indexe campos usados fora da travessia;
- teste com volume parecido com o esperado;
- observe tempo, memória e cardinalidade;
- evite retornar subgrafos inteiros para o navegador.
Consultas “amigos de amigos de amigos” crescem rapidamente. A pergunta de produto deve determinar até onde percorrer.
Como pedir ajuda à IA para modelar um grafo
Modele em SurrealDB um marketplace brasileiro de serviços locais.
Antes do schema, responda:
- quais perguntas do produto realmente exigem travessia de grafo?
- quais conexões devem ser record links simples?
- quais relações carregam dados próprios?
- onde precisamos de unicidade e idempotência?
- quais dados pessoais exigem retenção e acesso restrito?
Depois entregue:
- nós e arestas;
- schema SCHEMAFULL;
- três consultas críticas;
- índices necessários;
- cinco testes negativos;
- riscos de performance.
Não use grafo apenas para demonstrar a tecnologia.
Esse último requisito é importante. Um grafo ruim apenas troca joins compreensíveis por setas difíceis de manter.
Perguntas frequentes sobre grafos no SurrealDB
SurrealDB é um banco de grafos?
Ele é multi-modelo e inclui recursos nativos de grafo. Isso permite combinar relações com documentos, consultas estruturadas e vetores no mesmo banco, sem limitar todo dado a uma única representação.
Toda tabela de junção deve virar RELATE?
Não. Use relation table quando o vínculo tem significado próprio ou precisa ser percorrido como parte central do domínio. Uma referência simples pode continuar como campo de record.
Grafo é mais rápido que join?
Não existe resposta universal. Desempenho depende de modelo, cardinalidade, índices, profundidade e padrão de consulta. Faça benchmark com as perguntas reais do produto.
Posso combinar grafo e busca vetorial?
Sim. A busca vetorial encontra candidatos por significado; o grafo pode filtrar ou enriquecer por relações conhecidas. Esse é um dos padrões abordados em RAG e agentes com SurrealDB.
Modele as perguntas, não o diagrama bonito
Liste primeiro as perguntas que movem o produto: quem pode acessar, o que recomendar, como a pessoa chegou, qual caminho falta concluir. Só depois escolha nós e arestas.
Se você ainda está decidindo o banco, veja SurrealDB vs Postgres. Se já escolheu, comece com uma relação que tenha valor claro, dados próprios e um teste de unicidade.
Do vibe ao produto. Com método.



