Este guia demonstra como utilizar o módulo @redis/graph do ecossistema node-redis para interagir com o RedisGraph, a extensão de banco de dados de grafos do Redis, diretamente em aplicações Node.js. O foco está na execução de consultas Cypher para modelar e recuperar dados relacionais complexos.
Pré-requisitos e Configuração
Antes de começar, certifique-se de ter os seguintes componentes instalados:
- Node.js (versão 16 ou superior recomendada)
- Servidor Redis com o módulo RedisGraph carregado (Redis Stack 7.0+ inclui RedisGraph)
- Biblioteca
redispara Node.js (versão 4.x)
Instale os pacotes necessários via npm:
npm install redis @redis/graph
Conexão e Instanciação do Grafo
O primeiro passo é estabelecer uma conexão com o Redis e criar uma instância de grafo. O grafo é uma estrutura lógica dentro do Redis que agrupa nós e relacionamentos.
import { createClient } from 'redis';
import { Graph } from '@redis/graph';
const redisClient = createClient();
await redisClient.connect();
// Define um grafo lógico chamado 'catalogo_produtos'
const productGraph = new Graph(redisClient, 'catalogo_produtos');
Criando Nós e Relacionamentos
Utilize o método query para enviar comandos Cypher que modificam o grafo. A sintaxe define nós com labels (rótulos) e propriedades, conectados por relacionamentos direcionados.
await productGraph.query(`
CREATE
(tech:Category {nome: 'Eletronicos'}),
(laptop:Product {sku: 'LP001', nome: 'Notebook X1', preco: 4500}),
(phone:Product {sku: 'PH001', nome: 'Smartphone Z', preco: 2500}),
(laptop)-[:PERTENCE_A]->(tech),
(phone)-[:PERTENCE_A]->(tech),
(phone)-[:COMPATIVEL_COM]->(laptop)
`);
Consultas de Leitura
Para operações que apenas leem dados, use o método roQuery. Ele pode oferecer melhor desempenho ao evitar locks de escrita.
// Buscar produtos com preço superior a 3000
const result = await productGraph.roQuery(
'MATCH (p:Product) WHERE p.preco > $minPrice RETURN p.nome, p.preco ORDER BY p.preco DESC',
{ params: { minPrice: 3000 } }
);
console.log(result.data);
// Saída: [ { 'p.nome': 'Notebook X1', 'p.preco': 4500 } ]
Consultas com Padrões de Relacionamento
A verdadeira força dos grafos reside na navegação eficiente por relacionamentos.
// Encontrar todos os produtos compatíveis com produtos da categoria 'Eletronicos'
const compatibles = await productGraph.roQuery(`
MATCH (c:Category {nome: 'Eletronicos'})<-[:PERTENCE_A]-(p:Product)-[:COMPATIVEL_COM]->(comp)
RETURN p.nome AS produto, comp.nome AS compativel
`);
Otimização de Desempenho
Para consultas frequentes em propriedades específicas, crie índices para acelerar a busca.
await productGraph.query('CREATE INDEX FOR (p:Product) ON (p.sku)');
await productGraph.query('CREATE INDEX FOR (c:Category) ON (c.nome)');
Para inserções em massa, utilize transações (MULTI/EXEC) para agrupar múltiplos comandos.
const transaction = redisClient.multi();
transaction.graph.query('catalogo_produtos', 'CREATE (:Product {sku: "KP001", nome: "Teclado Mecanico"})');
transaction.graph.query('catalogo_produtos', 'CREATE (:Product {sku: "MS001", nome: "Mouse Ergonomico"})');
await transaction.exec();
Gerenciamento e Limpeza de Dados
Para remover todos os nós e relacionamentos de um grafo específico, execute um comando de deleção em massa. Tenha cuidado, pois esta operação é irreversível.
// Limpa completamente o grafo 'catalogo_produtos'
await productGraph.query('MATCH (n) DETACH DELETE n');
Cenário de Aplicação: Sistema de Recomendação
Um modelo de grafos permite implementar recomendações baseadas em relacionamentos de forma intuitiva.
// Recomendar produtos frequentemente comprados juntos
const recommendations = await productGraph.roQuery(`
MATCH (user:User {id: $userId})-[:COMPROU]->(purchased)-[:FREQUENTEMENTE_COMPRADO_JUNTO]->(recommended)
WHERE NOT (user)-[:COMPROU]->(recommended)
RETURN recommended.nome AS recomendacao, count(*) AS relevancia
ORDER BY relevancia DESC LIMIT 3
`, { params: { userId: 123 } });