Graph - Graph Database
Managed graph database powered by ArangoDB for modeling relationships, knowledge graphs, and interconnected data.
Overview
Graph provides a managed graph database optimized for:
- Knowledge graphs and ontologies
- Social networks and relationships
- Recommendation engines
- Fraud detection
- Network analysis
Quick Start
import { Tenzro } from '@tenzro/cloud';const client = new Tenzro({apiKey: process.env.TENZRO_API_KEY,projectId: 'your-project-id',});// Get graph database by nameconst graph = await client.graph.db('knowledge-graph');// Create nodesconst alice = await graph.createNode(['Person'], {name: 'Alice',age: 30});const bob = await graph.createNode(['Person'], {name: 'Bob',age: 25});// Create edges (relationships)await graph.createEdge(alice.id, bob.id, 'KNOWS', {since: 2020});// Find connected nodesconst friends = await graph.findConnected(alice.id, 'out', 'KNOWS');console.log(friends.nodes); // [{ id: '...', labels: ['Person'], properties: { name: 'Bob', ... } }]// Execute raw graph queries (AQL)const result = await graph.query(`FOR person IN PersonFILTER person.age >= 25RETURN person`);console.log(result.data);
SDK Reference
Get Database
// Get existing graph database by nameconst graph = await client.graph.db('knowledge-graph');
Node Operations
Create Node
const node = await graph.createNode(['Person', 'Employee'], // Labels{ name: 'Alice', age: 30 } // Properties);
Find Nodes
// Find all nodes with labelconst people = await graph.findNodes('Person');// Find nodes with filtersconst adults = await graph.findNodes('Person', {age: { $gte: 18 }});
Delete Node
await graph.deleteNode(nodeId);
Edge Operations
Create Edge
const edge = await graph.createEdge(startNodeId,endNodeId,'KNOWS', // Edge type{ since: 2020 } // Properties);
Find Connected Nodes
const result = await graph.findConnected(nodeId,'out', // 'in', 'out', or 'both''KNOWS', // Optional: edge type filter2 // Optional: traversal depth);// Returns: { nodes: GraphNode[], edges: GraphEdge[] }
Delete Edge
await graph.deleteEdge(edgeId);
Raw Query
const result = await graph.query('FOR p IN Person FILTER p.age > @minAge RETURN p',{ minAge: 18 } // Bind variables);// Returns: { data: any, executionTimeMs: number }
AQL Query Language
ArangoDB uses AQL (ArangoDB Query Language), similar to SQL but designed for graphs:
Basic Queries
// Get all documentsFOR doc IN usersRETURN doc// Filter documentsFOR user IN usersFILTER user.age >= 18RETURN user// Sort and limitFOR user IN usersSORT user.created_at DESCLIMIT 10RETURN user// Project specific fieldsFOR user IN usersRETURN { name: user.name, email: user.email }
Graph Traversals
// Find direct connections (1 hop)FOR vertex IN 1..1 OUTBOUND 'users/user1' followsRETURN vertex// Find all connections (up to 3 hops)FOR vertex, edge, path IN 1..3 OUTBOUND 'users/user1' followsRETURN { user: vertex.name, distance: LENGTH(path.edges) }// Bidirectional traversalFOR vertex IN 1..2 ANY 'users/user1' knowsRETURN DISTINCT vertex// Shortest pathFOR path IN OUTBOUND SHORTEST_PATH 'users/user1' TO 'users/user100' followsRETURN path.vertices[*].name
Aggregations
// Count and groupFOR user IN usersCOLLECT city = user.city WITH COUNT INTO countRETURN { city, count }// Sum and averageFOR order IN ordersCOLLECT user = order.user_id AGGREGATE total = SUM(order.amount)RETURN { user, total }
Use Cases
Knowledge Graph
const graph = await client.graph.db('knowledge-graph');// Create entitiesconst apple = await graph.createNode(['Company'], {name: 'Apple Inc.',industry: 'Technology'});const tech = await graph.createNode(['Industry'], {name: 'Technology',sector: 'IT'});// Create relationshipawait graph.createEdge(apple.id, tech.id, 'BELONGS_TO', {since: 1976});// Query: Find all companies in technologyconst result = await graph.query(`FOR industry IN IndustryFILTER industry.name == 'Technology'FOR company IN 1..1 INBOUND industry BELONGS_TORETURN company.name`);console.log(result.data); // ['Apple Inc.', ...]
Recommendation Engine
// Find products bought by similar usersconst { data } = await tenzro.graph.query(graphDbId, `LET userProducts = (FOR product IN 1..1 OUTBOUND @userId purchasesRETURN product._key)FOR similarUser IN usersFILTER similarUser._key != @userIdLET commonProducts = (FOR product IN 1..1 OUTBOUND similarUser purchasesFILTER product._key IN userProductsRETURN 1)FILTER LENGTH(commonProducts) >= 3FOR recommendation IN 1..1 OUTBOUND similarUser purchasesFILTER recommendation._key NOT IN userProductsCOLLECT product = recommendation WITH COUNT INTO scoreSORT score DESCLIMIT 10RETURN { product: product.name, score }`, { userId: 'users/user1' });
Social Network
// Find friends of friends (not already connected)const { data } = await tenzro.graph.query(graphDbId, `LET directFriends = (FOR friend IN 1..1 ANY @userId followsRETURN friend._key)FOR fof IN 2..2 ANY @userId followsFILTER fof._key != @userIdFILTER fof._key NOT IN directFriendsCOLLECT person = fof WITH COUNT INTO mutualCountSORT mutualCount DESCLIMIT 20RETURN {name: person.name,mutualFriends: mutualCount}`, { userId: 'users/user1' });
Bind Variables
Always use bind variables for user input to prevent injection:
// Good - using bind variablesconst { data } = await tenzro.graph.query(graphDbId, `FOR user IN usersFILTER user.email == @emailRETURN user`, { email: userInput });// Bad - string interpolation (vulnerable)// Don't do this:// `FOR user IN users FILTER user.email == '${userInput}' RETURN user`
Best Practices
- Use document collections for nodes: Store entity data in document collections
- Use edge collections for relationships: Edges must have _from and _to fields
- Index traversal start points: Create indexes on _from and _to for edge collections
- Limit traversal depth: Use specific depths (1..3) instead of unbounded traversals
- Use bind variables: Always parameterize user input
- Batch mutations: Group multiple inserts/updates in single queries
Limits
| Resource | Limit |
|---|---|
| Max collections per database | 1000 |
| Max documents per collection | 100 million |
| Max traversal depth | 10 |
| Query timeout | 60 seconds |
| Max result size | 100 MB |