Preview
Preview Feature — This feature is currently in preview and under active development. APIs and functionality may change. We recommend testing thoroughly before using in production.
Indexes & Constraints
Learn how to create and manage indexes and constraints to optimize query performance and ensure data integrity in your graph database.
Quick Example
- TypeScript
- Java
- Go
- .NET
// Create a unique index on user emails
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
});
// Create a uniqueness constraint
await ductape.graph.createNodeConstraint({
name: 'unique_user_email',
type: NodeConstraintType.UNIQUE,
label: 'User',
properties: ['email'],
});
// List all indexes
const indexes = await ductape.graph.listIndexes();
console.log('Indexes:', indexes.indexes.length);
// Create a unique index on user emails
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email']
));
// Create a uniqueness constraint
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label", "User",
properties: ['email']
));
// List all indexes
Map<String, Object> indexes = ductape.graph.listIndexes();
System.out.println('Indexes:', indexes.indexes.length);
// Create a unique index on user emails
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
});
// Create a uniqueness constraint
client.graph.createNodeConstraint({
"name": "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label": "User",
properties: ['email'],
});
// List all indexes
indexes := client.graph.listIndexes();
fmt.Println('Indexes:', indexes.indexes.length);
// Create a unique index on user emails
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
});
// Create a uniqueness constraint
await ductape.graph.createNodeConstraint({
["name"] = "unique_user_email",
type: NodeConstraintType.UNIQUE,
["label"] = "User",
properties: ['email'],
});
// List all indexes
var indexes = await ductape.graph.listIndexes();
Console.WriteLine('Indexes:', indexes.indexes.length);
Why Indexes Matter
Indexes dramatically improve query performance:
Without Index:
- TypeScript
- Java
- Go
- .NET
// Scans all nodes in database (slow)
const user = await ductape.graph.findNodes({
labels: ['User'],
where: { email: 'alice@example.com' },
});
// Could take seconds with millions of nodes
// Scans all nodes in database (slow)
Map<String, Object> user = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of( "email", "alice@example.com" )
));
// Could take seconds with millions of nodes
// Scans all nodes in database (slow)
user := client.graph.findNodes({
labels: ['User'],
where: { "email": "alice@example.com" },
});
// Could take seconds with millions of nodes
// Scans all nodes in database (slow)
var user = await ductape.graph.findNodes({
labels: ['User'],
where: { ["email"] = "alice@example.com" },
});
// Could take seconds with millions of nodes
With Index:
- TypeScript
- Java
- Go
- .NET
// Uses index for instant lookup (fast)
const user = await ductape.graph.findNodes({
labels: ['User'],
where: { email: 'alice@example.com' },
});
// Milliseconds even with millions of nodes
// Uses index for instant lookup (fast)
Map<String, Object> user = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of( "email", "alice@example.com" )
));
// Milliseconds even with millions of nodes
// Uses index for instant lookup (fast)
user := client.graph.findNodes({
labels: ['User'],
where: { "email": "alice@example.com" },
});
// Milliseconds even with millions of nodes
// Uses index for instant lookup (fast)
var user = await ductape.graph.findNodes({
labels: ['User'],
where: { ["email"] = "alice@example.com" },
});
// Milliseconds even with millions of nodes
Node Indexes
Create Node Index
- TypeScript
- Java
- Go
- .NET
import { NodeIndexType } from '@ductape/sdk';
const result = await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
});
console.log('Index created:', result.created);
import Map.of( NodeIndexType ) from '@ductape/sdk';
Map<String, Object> result = ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email']
));
System.out.println('Index created:', result.created);
import { NodeIndexType } from '@ductape/sdk';
result := client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
});
fmt.Println('Index created:', result.created);
import { NodeIndexType } from '@ductape/sdk';
var result = await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
});
Console.WriteLine('Index created:', result.created);
Index Types
BTREE (Default)
Best for most queries with equality and range conditions:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_product_price',
type: NodeIndexType.BTREE,
label: 'Product',
properties: ['price'],
});
// Efficiently supports:
// - Equality: { price: 99.99 }
// - Range: { price: { $GTE: 50, $LTE: 100 } }
// - Sorting: orderBy price
ductape.graph.createNodeIndex(Map.of(
"name", "idx_product_price",
type: NodeIndexType.BTREE,
"label", "Product",
properties: ['price']
));
// Efficiently supports:
// - Equality: Map.of( "price", 99.99 )
// - Range: Map.of( price: Map.of( $"GTE", 50, $"LTE", 100 ) )
// - Sorting: orderBy price
client.graph.createNodeIndex({
"name": "idx_product_price",
type: NodeIndexType.BTREE,
"label": "Product",
properties: ['price'],
});
// Efficiently supports:
// - Equality: { "price": 99.99 }
// - Range: { price: { $"GTE": 50, $"LTE": 100 } }
// - Sorting: orderBy price
await ductape.graph.createNodeIndex({
["name"] = "idx_product_price",
type: NodeIndexType.BTREE,
["label"] = "Product",
properties: ['price'],
});
// Efficiently supports:
// - Equality: { ["price"] = 99.99 }
// - Range: { price: { $["GTE"] = 50, $["LTE"] = 100 } }
// - Sorting: orderBy price
FULLTEXT
For text search capabilities:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_article_content',
type: NodeIndexType.FULLTEXT,
label: 'Article',
properties: ['title', 'content'],
});
// Use with full-text search
const results = await ductape.graph.fullTextSearch({
label: 'Article',
query: 'graph databases',
properties: ['title', 'content'],
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_article_content",
type: NodeIndexType.FULLTEXT,
"label", "Article",
properties: ['title', 'content']
));
// Use with full-text search
Map<String, Object> results = ductape.graph.fullTextSearch(Map.of(
"label", "Article",
"query", "graph databases",
properties: ['title', 'content']
));
client.graph.createNodeIndex({
"name": "idx_article_content",
type: NodeIndexType.FULLTEXT,
"label": "Article",
properties: ['title', 'content'],
});
// Use with full-text search
results := client.graph.fullTextSearch({
"label": "Article",
"query": "graph databases",
properties: ['title', 'content'],
});
await ductape.graph.createNodeIndex({
["name"] = "idx_article_content",
type: NodeIndexType.FULLTEXT,
["label"] = "Article",
properties: ['title', 'content'],
});
// Use with full-text search
var results = await ductape.graph.fullTextSearch({
["label"] = "Article",
["query"] = "graph databases",
properties: ['title', 'content'],
});
RANGE
Optimized for range queries (Neo4j):
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_user_age',
type: NodeIndexType.RANGE,
label: 'User',
properties: ['age'],
});
// Optimized for range conditions
const adults = await ductape.graph.findNodes({
labels: ['User'],
where: { age: { $GTE: 18, $LTE: 65 } },
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_age",
type: NodeIndexType.RANGE,
"label", "User",
properties: ['age']
));
// Optimized for range conditions
Map<String, Object> adults = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of( age: Map.of( $"GTE", 18, $"LTE", 65 ) )
));
client.graph.createNodeIndex({
"name": "idx_user_age",
type: NodeIndexType.RANGE,
"label": "User",
properties: ['age'],
});
// Optimized for range conditions
adults := client.graph.findNodes({
labels: ['User'],
where: { age: { $"GTE": 18, $"LTE": 65 } },
});
await ductape.graph.createNodeIndex({
["name"] = "idx_user_age",
type: NodeIndexType.RANGE,
["label"] = "User",
properties: ['age'],
});
// Optimized for range conditions
var adults = await ductape.graph.findNodes({
labels: ['User'],
where: { age: { $["GTE"] = 18, $["LTE"] = 65 } },
});
TEXT
For string pattern matching:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_user_name',
type: NodeIndexType.TEXT,
label: 'User',
properties: ['name'],
});
// Efficient for CONTAINS, STARTS_WITH, ENDS_WITH
const users = await ductape.graph.findNodes({
labels: ['User'],
where: {
name: { $CONTAINS: 'John' },
},
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_name",
type: NodeIndexType.TEXT,
"label", "User",
properties: ['name']
));
// Efficient for CONTAINS, STARTS_WITH, ENDS_WITH
Map<String, Object> users = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of(
name: Map.of( $"CONTAINS", "John" )
)
));
client.graph.createNodeIndex({
"name": "idx_user_name",
type: NodeIndexType.TEXT,
"label": "User",
properties: ['name'],
});
// Efficient for CONTAINS, STARTS_WITH, ENDS_WITH
users := client.graph.findNodes({
labels: ['User'],
where: {
name: { $"CONTAINS": "John" },
},
});
await ductape.graph.createNodeIndex({
["name"] = "idx_user_name",
type: NodeIndexType.TEXT,
["label"] = "User",
properties: ['name'],
});
// Efficient for CONTAINS, STARTS_WITH, ENDS_WITH
var users = await ductape.graph.findNodes({
labels: ['User'],
where: {
name: { $["CONTAINS"] = "John" },
},
});
POINT (Spatial)
For geospatial queries:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_store_location',
type: NodeIndexType.POINT,
label: 'Store',
properties: ['location'],
});
// Use for spatial queries
const nearbyStores = await ductape.graph.findNodes({
labels: ['Store'],
where: {
location: {
$NEAR: { lat: 37.7749, lon: -122.4194, distance: 5000 },
},
},
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_store_location",
type: NodeIndexType.POINT,
"label", "Store",
properties: ['location']
));
// Use for spatial queries
Map<String, Object> nearbyStores = ductape.graph.findNodes(Map.of(
labels: ['Store'],
where: Map.of(
location: Map.of(
$NEAR: Map.of( "lat", 37.7749, lon: -122.4194, "distance", 5000 )
)
)
));
client.graph.createNodeIndex({
"name": "idx_store_location",
type: NodeIndexType.POINT,
"label": "Store",
properties: ['location'],
});
// Use for spatial queries
nearbyStores := client.graph.findNodes({
labels: ['Store'],
where: {
location: {
$NEAR: { "lat": 37.7749, lon: -122.4194, "distance": 5000 },
},
},
});
await ductape.graph.createNodeIndex({
["name"] = "idx_store_location",
type: NodeIndexType.POINT,
["label"] = "Store",
properties: ['location'],
});
// Use for spatial queries
var nearbyStores = await ductape.graph.findNodes({
labels: ['Store'],
where: {
location: {
$NEAR: { ["lat"] = 37.7749, lon: -122.4194, ["distance"] = 5000 },
},
},
});
Composite Indexes
Index multiple properties together:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_user_city_age',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['city', 'age'],
});
// Efficient for queries filtering both properties
const users = await ductape.graph.findNodes({
labels: ['User'],
where: {
city: 'San Francisco',
age: { $GTE: 25 },
},
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_city_age",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['city', 'age']
));
// Efficient for queries filtering both properties
Map<String, Object> users = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of(
"city", "San Francisco",
age: Map.of( $"GTE", 25 )
)
));
client.graph.createNodeIndex({
"name": "idx_user_city_age",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['city', 'age'],
});
// Efficient for queries filtering both properties
users := client.graph.findNodes({
labels: ['User'],
where: {
"city": "San Francisco",
age: { $"GTE": 25 },
},
});
await ductape.graph.createNodeIndex({
["name"] = "idx_user_city_age",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['city', 'age'],
});
// Efficient for queries filtering both properties
var users = await ductape.graph.findNodes({
labels: ['User'],
where: {
["city"] = "San Francisco",
age: { $["GTE"] = 25 },
},
});
Index Options
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeIndex({
name: 'idx_custom',
type: NodeIndexType.BTREE,
label: 'Product',
properties: ['category'],
options: {
// Database-specific options
indexProvider: 'native-btree-1.0',
indexConfig: {
'spatial.cartesian.min': [-100.0, -100.0],
'spatial.cartesian.max': [100.0, 100.0],
},
},
});
ductape.graph.createNodeIndex(Map.of(
"name", "idx_custom",
type: NodeIndexType.BTREE,
"label", "Product",
properties: ['category'],
options: Map.of(
// Database-specific options
"indexProvider", "native-btree-1.0",
indexConfig: Map.of(
'spatial.cartesian.min': [-100.0, -100.0],
'spatial.cartesian.max': [100.0, 100.0]
)
)
));
client.graph.createNodeIndex({
"name": "idx_custom",
type: NodeIndexType.BTREE,
"label": "Product",
properties: ['category'],
options: {
// Database-specific options
"indexProvider": "native-btree-1.0",
indexConfig: {
'spatial.cartesian.min': [-100.0, -100.0],
'spatial.cartesian.max': [100.0, 100.0],
},
},
});
await ductape.graph.createNodeIndex({
["name"] = "idx_custom",
type: NodeIndexType.BTREE,
["label"] = "Product",
properties: ['category'],
options: {
// Database-specific options
["indexProvider"] = "native-btree-1.0",
indexConfig: {
'spatial.cartesian.min': [-100.0, -100.0],
'spatial.cartesian.max': [100.0, 100.0],
},
},
});
Relationship Indexes
Create Relationship Index
- TypeScript
- Java
- Go
- .NET
import { RelationshipIndexType } from '@ductape/sdk';
await ductape.graph.createRelationshipIndex({
name: 'idx_friendship_since',
type: RelationshipIndexType.BTREE,
relationshipType: 'FRIENDS_WITH',
properties: ['since'],
});
// Now efficient to query by relationship properties
const recentFriends = await ductape.graph.findRelationships({
type: 'FRIENDS_WITH',
where: {
since: { $GTE: new Date('2024-01-01') },
},
});
import Map.of( RelationshipIndexType ) from '@ductape/sdk';
ductape.graph.createRelationshipIndex(Map.of(
"name", "idx_friendship_since",
type: RelationshipIndexType.BTREE,
"relationshipType", "FRIENDS_WITH",
properties: ['since']
));
// Now efficient to query by relationship properties
Map<String, Object> recentFriends = ductape.graph.findRelationships(Map.of(
"type", "FRIENDS_WITH",
where: Map.of(
since: Map.of( $GTE: new Date('2024-01-01') )
)
));
import { RelationshipIndexType } from '@ductape/sdk';
client.graph.createRelationshipIndex({
"name": "idx_friendship_since",
type: RelationshipIndexType.BTREE,
"relationshipType": "FRIENDS_WITH",
properties: ['since'],
});
// Now efficient to query by relationship properties
recentFriends := client.graph.findRelationships({
"type": "FRIENDS_WITH",
where: {
since: { $GTE: new Date('2024-01-01') },
},
});
import { RelationshipIndexType } from '@ductape/sdk';
await ductape.graph.createRelationshipIndex({
["name"] = "idx_friendship_since",
type: RelationshipIndexType.BTREE,
["relationshipType"] = "FRIENDS_WITH",
properties: ['since'],
});
// Now efficient to query by relationship properties
var recentFriends = await ductape.graph.findRelationships({
["type"] = "FRIENDS_WITH",
where: {
since: { $GTE: new Date('2024-01-01') },
},
});
Relationship Index Types
- TypeScript
- Java
- Go
- .NET
// BTREE for general queries
await ductape.graph.createRelationshipIndex({
name: 'idx_order_total',
type: RelationshipIndexType.BTREE,
relationshipType: 'PURCHASED',
properties: ['total', 'date'],
});
// RANGE for range queries
await ductape.graph.createRelationshipIndex({
name: 'idx_weight',
type: RelationshipIndexType.RANGE,
relationshipType: 'INFLUENCES',
properties: ['weight'],
});
// BTREE for general queries
ductape.graph.createRelationshipIndex(Map.of(
"name", "idx_order_total",
type: RelationshipIndexType.BTREE,
"relationshipType", "PURCHASED",
properties: ['total', 'date']
));
// RANGE for range queries
ductape.graph.createRelationshipIndex(Map.of(
"name", "idx_weight",
type: RelationshipIndexType.RANGE,
"relationshipType", "INFLUENCES",
properties: ['weight']
));
// BTREE for general queries
client.graph.createRelationshipIndex({
"name": "idx_order_total",
type: RelationshipIndexType.BTREE,
"relationshipType": "PURCHASED",
properties: ['total', 'date'],
});
// RANGE for range queries
client.graph.createRelationshipIndex({
"name": "idx_weight",
type: RelationshipIndexType.RANGE,
"relationshipType": "INFLUENCES",
properties: ['weight'],
});
// BTREE for general queries
await ductape.graph.createRelationshipIndex({
["name"] = "idx_order_total",
type: RelationshipIndexType.BTREE,
["relationshipType"] = "PURCHASED",
properties: ['total', 'date'],
});
// RANGE for range queries
await ductape.graph.createRelationshipIndex({
["name"] = "idx_weight",
type: RelationshipIndexType.RANGE,
["relationshipType"] = "INFLUENCES",
properties: ['weight'],
});
Node Constraints
Constraints enforce data integrity and automatically create indexes.
Unique Constraint
Ensures property values are unique:
- TypeScript
- Java
- Go
- .NET
import { NodeConstraintType } from '@ductape/sdk';
await ductape.graph.createNodeConstraint({
name: 'unique_user_email',
type: NodeConstraintType.UNIQUE,
label: 'User',
properties: ['email'],
});
// Prevents duplicate emails
try {
await ductape.graph.createNode({
labels: ['User'],
properties: { email: 'alice@example.com' },
});
// This will fail - email already exists
await ductape.graph.createNode({
labels: ['User'],
properties: { email: 'alice@example.com' },
});
} catch (error) {
console.log('Constraint violation:', error.message);
}
import Map.of( NodeConstraintType ) from '@ductape/sdk';
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label", "User",
properties: ['email']
));
// Prevents duplicate emails
try Map.of(
ductape.graph.createNode(Map.of(
labels: ['User'],
properties: Map.of( "email", "alice@example.com" )
));
// This will fail - email already exists
ductape.graph.createNode(Map.of(
labels: ['User'],
properties: Map.of( "email", "alice@example.com" )
));
) catch (error) Map.of(
System.out.println('Constraint violation:', error.message);
)
import { NodeConstraintType } from '@ductape/sdk';
client.graph.createNodeConstraint({
"name": "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label": "User",
properties: ['email'],
});
// Prevents duplicate emails
try {
client.graph.createNode({
labels: ['User'],
properties: { "email": "alice@example.com" },
});
// This will fail - email already exists
client.graph.createNode({
labels: ['User'],
properties: { "email": "alice@example.com" },
});
} catch (error) {
fmt.Println('Constraint violation:', error.message);
}
import { NodeConstraintType } from '@ductape/sdk';
await ductape.graph.createNodeConstraint({
["name"] = "unique_user_email",
type: NodeConstraintType.UNIQUE,
["label"] = "User",
properties: ['email'],
});
// Prevents duplicate emails
try {
await ductape.graph.createNode({
labels: ['User'],
properties: { ["email"] = "alice@example.com" },
});
// This will fail - email already exists
await ductape.graph.createNode({
labels: ['User'],
properties: { ["email"] = "alice@example.com" },
});
} catch (error) {
Console.WriteLine('Constraint violation:', error.message);
}
Existence Constraint
Ensures properties must exist:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeConstraint({
name: 'user_email_exists',
type: NodeConstraintType.EXISTS,
label: 'User',
properties: ['email'],
});
// This will fail - email is required
try {
await ductape.graph.createNode({
labels: ['User'],
properties: { name: 'Bob' }, // Missing email
});
} catch (error) {
console.log('Email is required');
}
ductape.graph.createNodeConstraint(Map.of(
"name", "user_email_exists",
type: NodeConstraintType.EXISTS,
"label", "User",
properties: ['email']
));
// This will fail - email is required
try Map.of(
ductape.graph.createNode(Map.of(
labels: ['User'],
properties: Map.of( "name", "Bob" ), // Missing email
));
) catch (error) Map.of(
System.out.println('Email is required');
)
client.graph.createNodeConstraint({
"name": "user_email_exists",
type: NodeConstraintType.EXISTS,
"label": "User",
properties: ['email'],
});
// This will fail - email is required
try {
client.graph.createNode({
labels: ['User'],
properties: { "name": "Bob" }, // Missing email
});
} catch (error) {
fmt.Println('Email is required');
}
await ductape.graph.createNodeConstraint({
["name"] = "user_email_exists",
type: NodeConstraintType.EXISTS,
["label"] = "User",
properties: ['email'],
});
// This will fail - email is required
try {
await ductape.graph.createNode({
labels: ['User'],
properties: { ["name"] = "Bob" }, // Missing email
});
} catch (error) {
Console.WriteLine('Email is required');
}
Node Key Constraint
Composite uniqueness across multiple properties:
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createNodeConstraint({
name: 'unique_product_sku_vendor',
type: NodeConstraintType.NODE_KEY,
label: 'Product',
properties: ['sku', 'vendor'],
});
// SKU must be unique per vendor
// Same SKU can exist for different vendors
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_product_sku_vendor",
type: NodeConstraintType.NODE_KEY,
"label", "Product",
properties: ['sku', 'vendor']
));
// SKU must be unique per vendor
// Same SKU can exist for different vendors
client.graph.createNodeConstraint({
"name": "unique_product_sku_vendor",
type: NodeConstraintType.NODE_KEY,
"label": "Product",
properties: ['sku', 'vendor'],
});
// SKU must be unique per vendor
// Same SKU can exist for different vendors
await ductape.graph.createNodeConstraint({
["name"] = "unique_product_sku_vendor",
type: NodeConstraintType.NODE_KEY,
["label"] = "Product",
properties: ['sku', 'vendor'],
});
// SKU must be unique per vendor
// Same SKU can exist for different vendors
Relationship Constraints
Unique Relationship Constraint
- TypeScript
- Java
- Go
- .NET
import { RelationshipConstraintType } from '@ductape/sdk';
await ductape.graph.createRelationshipConstraint({
name: 'unique_follows',
type: RelationshipConstraintType.UNIQUE,
relationshipType: 'FOLLOWS',
properties: ['userId', 'followedId'],
});
// Prevents duplicate follow relationships
import Map.of( RelationshipConstraintType ) from '@ductape/sdk';
ductape.graph.createRelationshipConstraint(Map.of(
"name", "unique_follows",
type: RelationshipConstraintType.UNIQUE,
"relationshipType", "FOLLOWS",
properties: ['userId', 'followedId']
));
// Prevents duplicate follow relationships
import { RelationshipConstraintType } from '@ductape/sdk';
client.graph.createRelationshipConstraint({
"name": "unique_follows",
type: RelationshipConstraintType.UNIQUE,
"relationshipType": "FOLLOWS",
properties: ['userId', 'followedId'],
});
// Prevents duplicate follow relationships
import { RelationshipConstraintType } from '@ductape/sdk';
await ductape.graph.createRelationshipConstraint({
["name"] = "unique_follows",
type: RelationshipConstraintType.UNIQUE,
["relationshipType"] = "FOLLOWS",
properties: ['userId', 'followedId'],
});
// Prevents duplicate follow relationships
Relationship Property Existence
- TypeScript
- Java
- Go
- .NET
await ductape.graph.createRelationshipConstraint({
name: 'purchase_requires_date',
type: RelationshipConstraintType.EXISTS,
relationshipType: 'PURCHASED',
properties: ['date'],
});
// All PURCHASED relationships must have a date property
ductape.graph.createRelationshipConstraint(Map.of(
"name", "purchase_requires_date",
type: RelationshipConstraintType.EXISTS,
"relationshipType", "PURCHASED",
properties: ['date']
));
// All PURCHASED relationships must have a date property
client.graph.createRelationshipConstraint({
"name": "purchase_requires_date",
type: RelationshipConstraintType.EXISTS,
"relationshipType": "PURCHASED",
properties: ['date'],
});
// All PURCHASED relationships must have a date property
await ductape.graph.createRelationshipConstraint({
["name"] = "purchase_requires_date",
type: RelationshipConstraintType.EXISTS,
["relationshipType"] = "PURCHASED",
properties: ['date'],
});
// All PURCHASED relationships must have a date property
Managing Indexes
List All Indexes
- TypeScript
- Java
- Go
- .NET
const result = await ductape.graph.listIndexes();
console.log(`Total indexes: ${result.indexes.length}`);
result.indexes.forEach(index => {
console.log(`${index.name} on ${index.label || index.relationshipType}`);
console.log(` Type: ${index.type}`);
console.log(` Properties: ${index.properties.join(', ')}`);
console.log(` State: ${index.state}`);
});
Map<String, Object> result = ductape.graph.listIndexes();
System.out.println(`Total indexes: $Map.of(result.indexes.length)`);
result.indexes.forEach(index => Map.of(
System.out.println(`$Map.of(index.name) on $Map.of(index.label || index.relationshipType)`);
System.out.println(` Type: $Map.of(index.type)`);
System.out.println(` Properties: $Map.of(index.properties.join(', '))`);
System.out.println(` State: $Map.of(index.state)`);
));
result := client.graph.listIndexes();
fmt.Println(`Total indexes: ${result.indexes.length}`);
result.indexes.forEach(index => {
fmt.Println(`${index.name} on ${index.label || index.relationshipType}`);
fmt.Println(` Type: ${index.type}`);
fmt.Println(` Properties: ${index.properties.join(', ')}`);
fmt.Println(` State: ${index.state}`);
});
var result = await ductape.graph.listIndexes();
Console.WriteLine(`Total indexes: ${result.indexes.length}`);
result.indexes.forEach(index => {
Console.WriteLine(`${index.name} on ${index.label || index.relationshipType}`);
Console.WriteLine(` Type: ${index.type}`);
Console.WriteLine(` Properties: ${index.properties.join(', ')}`);
Console.WriteLine(` State: ${index.state}`);
});
Drop Index
- TypeScript
- Java
- Go
- .NET
const result = await ductape.graph.dropIndex('idx_user_email');
if (result.dropped) {
console.log('Index dropped successfully');
}
Map<String, Object> result = ductape.graph.dropIndex('idx_user_email');
if (result.dropped) Map.of(
System.out.println('Index dropped successfully');
)
result := client.graph.dropIndex('idx_user_email');
if (result.dropped) {
fmt.Println('Index dropped successfully');
}
var result = await ductape.graph.dropIndex('idx_user_email');
if (result.dropped) {
Console.WriteLine('Index dropped successfully');
}
List All Constraints
- TypeScript
- Java
- Go
- .NET
const result = await ductape.graph.listConstraints();
console.log(`Total constraints: ${result.constraints.length}`);
result.constraints.forEach(constraint => {
console.log(`${constraint.name}: ${constraint.type}`);
console.log(` On: ${constraint.label || constraint.relationshipType}`);
console.log(` Properties: ${constraint.properties.join(', ')}`);
});
Map<String, Object> result = ductape.graph.listConstraints();
System.out.println(`Total constraints: $Map.of(result.constraints.length)`);
result.constraints.forEach(constraint => Map.of(
System.out.println(`$Map.of(constraint.name): $Map.of(constraint.type)`);
System.out.println(` On: $Map.of(constraint.label || constraint.relationshipType)`);
System.out.println(` Properties: $Map.of(constraint.properties.join(', '))`);
));
result := client.graph.listConstraints();
fmt.Println(`Total constraints: ${result.constraints.length}`);
result.constraints.forEach(constraint => {
fmt.Println(`${constraint.name}: ${constraint.type}`);
fmt.Println(` On: ${constraint.label || constraint.relationshipType}`);
fmt.Println(` Properties: ${constraint.properties.join(', ')}`);
});
var result = await ductape.graph.listConstraints();
Console.WriteLine(`Total constraints: ${result.constraints.length}`);
result.constraints.forEach(constraint => {
Console.WriteLine(`${constraint.name}: ${constraint.type}`);
Console.WriteLine(` On: ${constraint.label || constraint.relationshipType}`);
Console.WriteLine(` Properties: ${constraint.properties.join(', ')}`);
});
Drop Constraint
- TypeScript
- Java
- Go
- .NET
const result = await ductape.graph.dropConstraint('unique_user_email');
if (result.dropped) {
console.log('Constraint dropped successfully');
}
Map<String, Object> result = ductape.graph.dropConstraint('unique_user_email');
if (result.dropped) Map.of(
System.out.println('Constraint dropped successfully');
)
result := client.graph.dropConstraint('unique_user_email');
if (result.dropped) {
fmt.Println('Constraint dropped successfully');
}
var result = await ductape.graph.dropConstraint('unique_user_email');
if (result.dropped) {
Console.WriteLine('Constraint dropped successfully');
}
Best Practices
1. Index Frequently Queried Properties
- TypeScript
- Java
- Go
- .NET
// Good - index properties used in WHERE clauses
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
});
// Also index properties used in JOINs/traversals
await ductape.graph.createNodeIndex({
name: 'idx_user_id',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['userId'],
});
// Good - index properties used in WHERE clauses
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email']
));
// Also index properties used in JOINs/traversals
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_id",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['userId']
));
// Good - index properties used in WHERE clauses
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
});
// Also index properties used in JOINs/traversals
client.graph.createNodeIndex({
"name": "idx_user_id",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['userId'],
});
// Good - index properties used in WHERE clauses
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
});
// Also index properties used in JOINs/traversals
await ductape.graph.createNodeIndex({
["name"] = "idx_user_id",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['userId'],
});
2. Use Constraints for Data Integrity
- TypeScript
- Java
- Go
- .NET
// Prevent duplicate emails at database level
await ductape.graph.createNodeConstraint({
name: 'unique_user_email',
type: NodeConstraintType.UNIQUE,
label: 'User',
properties: ['email'],
});
// Ensure critical properties always exist
await ductape.graph.createNodeConstraint({
name: 'user_required_fields',
type: NodeConstraintType.EXISTS,
label: 'User',
properties: ['email', 'createdAt'],
});
// Prevent duplicate emails at database level
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label", "User",
properties: ['email']
));
// Ensure critical properties always exist
ductape.graph.createNodeConstraint(Map.of(
"name", "user_required_fields",
type: NodeConstraintType.EXISTS,
"label", "User",
properties: ['email', 'createdAt']
));
// Prevent duplicate emails at database level
client.graph.createNodeConstraint({
"name": "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label": "User",
properties: ['email'],
});
// Ensure critical properties always exist
client.graph.createNodeConstraint({
"name": "user_required_fields",
type: NodeConstraintType.EXISTS,
"label": "User",
properties: ['email', 'createdAt'],
});
// Prevent duplicate emails at database level
await ductape.graph.createNodeConstraint({
["name"] = "unique_user_email",
type: NodeConstraintType.UNIQUE,
["label"] = "User",
properties: ['email'],
});
// Ensure critical properties always exist
await ductape.graph.createNodeConstraint({
["name"] = "user_required_fields",
type: NodeConstraintType.EXISTS,
["label"] = "User",
properties: ['email', 'createdAt'],
});
3. Composite Indexes for Multiple Filters
- TypeScript
- Java
- Go
- .NET
// If you often query by city AND status together
await ductape.graph.createNodeIndex({
name: 'idx_user_city_status',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['city', 'status'],
});
// Efficient for:
const users = await ductape.graph.findNodes({
labels: ['User'],
where: {
city: 'New York',
status: 'active',
},
});
// If you often query by city AND status together
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_city_status",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['city', 'status']
));
// Efficient for:
Map<String, Object> users = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of(
"city", "New York",
"status", "active"
)
));
// If you often query by city AND status together
client.graph.createNodeIndex({
"name": "idx_user_city_status",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['city', 'status'],
});
// Efficient for:
users := client.graph.findNodes({
labels: ['User'],
where: {
"city": "New York",
"status": "active",
},
});
// If you often query by city AND status together
await ductape.graph.createNodeIndex({
["name"] = "idx_user_city_status",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['city', 'status'],
});
// Efficient for:
var users = await ductape.graph.findNodes({
labels: ['User'],
where: {
["city"] = "New York",
["status"] = "active",
},
});
4. Choose the Right Index Type
- TypeScript
- Java
- Go
- .NET
// BTREE for equality and ranges
await ductape.graph.createNodeIndex({
name: 'idx_price',
type: NodeIndexType.BTREE,
label: 'Product',
properties: ['price'],
});
// FULLTEXT for text search
await ductape.graph.createNodeIndex({
name: 'idx_content',
type: NodeIndexType.FULLTEXT,
label: 'Article',
properties: ['content'],
});
// TEXT for pattern matching
await ductape.graph.createNodeIndex({
name: 'idx_name',
type: NodeIndexType.TEXT,
label: 'User',
properties: ['name'],
});
// BTREE for equality and ranges
ductape.graph.createNodeIndex(Map.of(
"name", "idx_price",
type: NodeIndexType.BTREE,
"label", "Product",
properties: ['price']
));
// FULLTEXT for text search
ductape.graph.createNodeIndex(Map.of(
"name", "idx_content",
type: NodeIndexType.FULLTEXT,
"label", "Article",
properties: ['content']
));
// TEXT for pattern matching
ductape.graph.createNodeIndex(Map.of(
"name", "idx_name",
type: NodeIndexType.TEXT,
"label", "User",
properties: ['name']
));
// BTREE for equality and ranges
client.graph.createNodeIndex({
"name": "idx_price",
type: NodeIndexType.BTREE,
"label": "Product",
properties: ['price'],
});
// FULLTEXT for text search
client.graph.createNodeIndex({
"name": "idx_content",
type: NodeIndexType.FULLTEXT,
"label": "Article",
properties: ['content'],
});
// TEXT for pattern matching
client.graph.createNodeIndex({
"name": "idx_name",
type: NodeIndexType.TEXT,
"label": "User",
properties: ['name'],
});
// BTREE for equality and ranges
await ductape.graph.createNodeIndex({
["name"] = "idx_price",
type: NodeIndexType.BTREE,
["label"] = "Product",
properties: ['price'],
});
// FULLTEXT for text search
await ductape.graph.createNodeIndex({
["name"] = "idx_content",
type: NodeIndexType.FULLTEXT,
["label"] = "Article",
properties: ['content'],
});
// TEXT for pattern matching
await ductape.graph.createNodeIndex({
["name"] = "idx_name",
type: NodeIndexType.TEXT,
["label"] = "User",
properties: ['name'],
});
5. Don't Over-Index
- TypeScript
- Java
- Go
- .NET
// Bad - too many indexes slow down writes
// Only index what you actually query
// Good - strategic indexing
// Index high-cardinality, frequently queried properties
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'], // High cardinality, frequently queried
});
// Skip indexing low-cardinality properties (unless required)
// Don't index: gender (only 2-3 values), isActive (boolean)
// Bad - too many indexes slow down writes
// Only index what you actually query
// Good - strategic indexing
// Index high-cardinality, frequently queried properties
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email'], // High cardinality, frequently queried
));
// Skip indexing low-cardinality properties (unless required)
// Don't index: gender (only 2-3 values), isActive (boolean)
// Bad - too many indexes slow down writes
// Only index what you actually query
// Good - strategic indexing
// Index high-cardinality, frequently queried properties
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'], // High cardinality, frequently queried
});
// Skip indexing low-cardinality properties (unless required)
// Don't index: gender (only 2-3 values), isActive (boolean)
// Bad - too many indexes slow down writes
// Only index what you actually query
// Good - strategic indexing
// Index high-cardinality, frequently queried properties
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'], // High cardinality, frequently queried
});
// Skip indexing low-cardinality properties (unless required)
// Don't index: gender (only 2-3 values), isActive (boolean)
6. Index Property Order Matters
- TypeScript
- Java
- Go
- .NET
// Property order in composite indexes matters!
// Good - most selective property first
await ductape.graph.createNodeIndex({
name: 'idx_user_email_city',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email', 'city'], // email is more selective
});
// This efficiently supports:
// - { email: 'x@y.com' }
// - { email: 'x@y.com', city: 'NYC' }
// But NOT efficient for:
// - { city: 'NYC' } alone (first property not in filter)
// Property order in composite indexes matters!
// Good - most selective property first
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email_city",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email', 'city'], // email is more selective
));
// This efficiently supports:
// - Map.of( "email", "x@y.com" )
// - Map.of( "email", "x@y.com", "city", "NYC" )
// But NOT efficient for:
// - Map.of( "city", "NYC" ) alone (first property not in filter)
// Property order in composite indexes matters!
// Good - most selective property first
client.graph.createNodeIndex({
"name": "idx_user_email_city",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email', 'city'], // email is more selective
});
// This efficiently supports:
// - { "email": "x@y.com" }
// - { "email": "x@y.com", "city": "NYC" }
// But NOT efficient for:
// - { "city": "NYC" } alone (first property not in filter)
// Property order in composite indexes matters!
// Good - most selective property first
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email_city",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email', 'city'], // email is more selective
});
// This efficiently supports:
// - { ["email"] = "x@y.com" }
// - { ["email"] = "x@y.com", ["city"] = "NYC" }
// But NOT efficient for:
// - { ["city"] = "NYC" } alone (first property not in filter)
7. Monitor Index Usage
- TypeScript
- Java
- Go
- .NET
// Regularly review your indexes
const indexes = await ductape.graph.listIndexes();
// Check which are actually being used
// Drop unused indexes to improve write performance
for (const index of indexes.indexes) {
if (index.state !== 'ONLINE') {
console.log(`Index ${index.name} is not online`);
}
}
// Regularly review your indexes
Map<String, Object> indexes = ductape.graph.listIndexes();
// Check which are actually being used
// Drop unused indexes to improve write performance
for (Map<String, Object> index of indexes.indexes) Map.of(
if (index.state !== 'ONLINE') Map.of(
System.out.println(`Index $Map.of(index.name) is not online`);
)
)
// Regularly review your indexes
indexes := client.graph.listIndexes();
// Check which are actually being used
// Drop unused indexes to improve write performance
for (const index of indexes.indexes) {
if (index.state !== 'ONLINE') {
fmt.Println(`Index ${index.name} is not online`);
}
}
// Regularly review your indexes
var indexes = await ductape.graph.listIndexes();
// Check which are actually being used
// Drop unused indexes to improve write performance
for (var index of indexes.indexes) {
if (index.state !== 'ONLINE') {
Console.WriteLine(`Index ${index.name} is not online`);
}
}
Common Patterns
User System
- TypeScript
- Java
- Go
- .NET
// Unique email for login
await ductape.graph.createNodeConstraint({
name: 'unique_user_email',
type: NodeConstraintType.UNIQUE,
label: 'User',
properties: ['email'],
});
// Index for user lookups
await ductape.graph.createNodeIndex({
name: 'idx_user_username',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['username'],
});
// Index for status filtering
await ductape.graph.createNodeIndex({
name: 'idx_user_status_created',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['status', 'createdAt'],
});
// Unique email for login
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label", "User",
properties: ['email']
));
// Index for user lookups
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_username",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['username']
));
// Index for status filtering
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_status_created",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['status', 'createdAt']
));
// Unique email for login
client.graph.createNodeConstraint({
"name": "unique_user_email",
type: NodeConstraintType.UNIQUE,
"label": "User",
properties: ['email'],
});
// Index for user lookups
client.graph.createNodeIndex({
"name": "idx_user_username",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['username'],
});
// Index for status filtering
client.graph.createNodeIndex({
"name": "idx_user_status_created",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['status', 'createdAt'],
});
// Unique email for login
await ductape.graph.createNodeConstraint({
["name"] = "unique_user_email",
type: NodeConstraintType.UNIQUE,
["label"] = "User",
properties: ['email'],
});
// Index for user lookups
await ductape.graph.createNodeIndex({
["name"] = "idx_user_username",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['username'],
});
// Index for status filtering
await ductape.graph.createNodeIndex({
["name"] = "idx_user_status_created",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['status', 'createdAt'],
});
E-Commerce
- TypeScript
- Java
- Go
- .NET
// Unique product SKUs
await ductape.graph.createNodeConstraint({
name: 'unique_product_sku',
type: NodeConstraintType.UNIQUE,
label: 'Product',
properties: ['sku'],
});
// Index for product search
await ductape.graph.createNodeIndex({
name: 'idx_product_name',
type: NodeIndexType.TEXT,
label: 'Product',
properties: ['name'],
});
// Index for category browsing
await ductape.graph.createNodeIndex({
name: 'idx_product_category_price',
type: NodeIndexType.BTREE,
label: 'Product',
properties: ['category', 'price'],
});
// Full-text search for products
await ductape.graph.createNodeIndex({
name: 'idx_product_description',
type: NodeIndexType.FULLTEXT,
label: 'Product',
properties: ['name', 'description'],
});
// Unique product SKUs
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_product_sku",
type: NodeConstraintType.UNIQUE,
"label", "Product",
properties: ['sku']
));
// Index for product search
ductape.graph.createNodeIndex(Map.of(
"name", "idx_product_name",
type: NodeIndexType.TEXT,
"label", "Product",
properties: ['name']
));
// Index for category browsing
ductape.graph.createNodeIndex(Map.of(
"name", "idx_product_category_price",
type: NodeIndexType.BTREE,
"label", "Product",
properties: ['category', 'price']
));
// Full-text search for products
ductape.graph.createNodeIndex(Map.of(
"name", "idx_product_description",
type: NodeIndexType.FULLTEXT,
"label", "Product",
properties: ['name', 'description']
));
// Unique product SKUs
client.graph.createNodeConstraint({
"name": "unique_product_sku",
type: NodeConstraintType.UNIQUE,
"label": "Product",
properties: ['sku'],
});
// Index for product search
client.graph.createNodeIndex({
"name": "idx_product_name",
type: NodeIndexType.TEXT,
"label": "Product",
properties: ['name'],
});
// Index for category browsing
client.graph.createNodeIndex({
"name": "idx_product_category_price",
type: NodeIndexType.BTREE,
"label": "Product",
properties: ['category', 'price'],
});
// Full-text search for products
client.graph.createNodeIndex({
"name": "idx_product_description",
type: NodeIndexType.FULLTEXT,
"label": "Product",
properties: ['name', 'description'],
});
// Unique product SKUs
await ductape.graph.createNodeConstraint({
["name"] = "unique_product_sku",
type: NodeConstraintType.UNIQUE,
["label"] = "Product",
properties: ['sku'],
});
// Index for product search
await ductape.graph.createNodeIndex({
["name"] = "idx_product_name",
type: NodeIndexType.TEXT,
["label"] = "Product",
properties: ['name'],
});
// Index for category browsing
await ductape.graph.createNodeIndex({
["name"] = "idx_product_category_price",
type: NodeIndexType.BTREE,
["label"] = "Product",
properties: ['category', 'price'],
});
// Full-text search for products
await ductape.graph.createNodeIndex({
["name"] = "idx_product_description",
type: NodeIndexType.FULLTEXT,
["label"] = "Product",
properties: ['name', 'description'],
});
Social Network
- TypeScript
- Java
- Go
- .NET
// Unique usernames
await ductape.graph.createNodeConstraint({
name: 'unique_username',
type: NodeConstraintType.UNIQUE,
label: 'User',
properties: ['username'],
});
// Index friendship dates
await ductape.graph.createRelationshipIndex({
name: 'idx_friendship_since',
type: RelationshipIndexType.BTREE,
relationshipType: 'FRIENDS_WITH',
properties: ['since'],
});
// Index for feed queries
await ductape.graph.createNodeIndex({
name: 'idx_post_created',
type: NodeIndexType.BTREE,
label: 'Post',
properties: ['createdAt'],
});
// Unique usernames
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_username",
type: NodeConstraintType.UNIQUE,
"label", "User",
properties: ['username']
));
// Index friendship dates
ductape.graph.createRelationshipIndex(Map.of(
"name", "idx_friendship_since",
type: RelationshipIndexType.BTREE,
"relationshipType", "FRIENDS_WITH",
properties: ['since']
));
// Index for feed queries
ductape.graph.createNodeIndex(Map.of(
"name", "idx_post_created",
type: NodeIndexType.BTREE,
"label", "Post",
properties: ['createdAt']
));
// Unique usernames
client.graph.createNodeConstraint({
"name": "unique_username",
type: NodeConstraintType.UNIQUE,
"label": "User",
properties: ['username'],
});
// Index friendship dates
client.graph.createRelationshipIndex({
"name": "idx_friendship_since",
type: RelationshipIndexType.BTREE,
"relationshipType": "FRIENDS_WITH",
properties: ['since'],
});
// Index for feed queries
client.graph.createNodeIndex({
"name": "idx_post_created",
type: NodeIndexType.BTREE,
"label": "Post",
properties: ['createdAt'],
});
// Unique usernames
await ductape.graph.createNodeConstraint({
["name"] = "unique_username",
type: NodeConstraintType.UNIQUE,
["label"] = "User",
properties: ['username'],
});
// Index friendship dates
await ductape.graph.createRelationshipIndex({
["name"] = "idx_friendship_since",
type: RelationshipIndexType.BTREE,
["relationshipType"] = "FRIENDS_WITH",
properties: ['since'],
});
// Index for feed queries
await ductape.graph.createNodeIndex({
["name"] = "idx_post_created",
type: NodeIndexType.BTREE,
["label"] = "Post",
properties: ['createdAt'],
});
Content Management
- TypeScript
- Java
- Go
- .NET
// Unique slugs for URLs
await ductape.graph.createNodeConstraint({
name: 'unique_article_slug',
type: NodeConstraintType.UNIQUE,
label: 'Article',
properties: ['slug'],
});
// Full-text search
await ductape.graph.createNodeIndex({
name: 'idx_article_search',
type: NodeIndexType.FULLTEXT,
label: 'Article',
properties: ['title', 'content', 'tags'],
});
// Index for filtering
await ductape.graph.createNodeIndex({
name: 'idx_article_status_published',
type: NodeIndexType.BTREE,
label: 'Article',
properties: ['status', 'publishedAt'],
});
// Unique slugs for URLs
ductape.graph.createNodeConstraint(Map.of(
"name", "unique_article_slug",
type: NodeConstraintType.UNIQUE,
"label", "Article",
properties: ['slug']
));
// Full-text search
ductape.graph.createNodeIndex(Map.of(
"name", "idx_article_search",
type: NodeIndexType.FULLTEXT,
"label", "Article",
properties: ['title', 'content', 'tags']
));
// Index for filtering
ductape.graph.createNodeIndex(Map.of(
"name", "idx_article_status_published",
type: NodeIndexType.BTREE,
"label", "Article",
properties: ['status', 'publishedAt']
));
// Unique slugs for URLs
client.graph.createNodeConstraint({
"name": "unique_article_slug",
type: NodeConstraintType.UNIQUE,
"label": "Article",
properties: ['slug'],
});
// Full-text search
client.graph.createNodeIndex({
"name": "idx_article_search",
type: NodeIndexType.FULLTEXT,
"label": "Article",
properties: ['title', 'content', 'tags'],
});
// Index for filtering
client.graph.createNodeIndex({
"name": "idx_article_status_published",
type: NodeIndexType.BTREE,
"label": "Article",
properties: ['status', 'publishedAt'],
});
// Unique slugs for URLs
await ductape.graph.createNodeConstraint({
["name"] = "unique_article_slug",
type: NodeConstraintType.UNIQUE,
["label"] = "Article",
properties: ['slug'],
});
// Full-text search
await ductape.graph.createNodeIndex({
["name"] = "idx_article_search",
type: NodeIndexType.FULLTEXT,
["label"] = "Article",
properties: ['title', 'content', 'tags'],
});
// Index for filtering
await ductape.graph.createNodeIndex({
["name"] = "idx_article_status_published",
type: NodeIndexType.BTREE,
["label"] = "Article",
properties: ['status', 'publishedAt'],
});
Performance Impact
Write Performance
Indexes slow down writes slightly:
- TypeScript
- Java
- Go
- .NET
// No indexes: Fast writes, slow reads
// With 1 index: Slightly slower writes, fast reads
// With 5 indexes: Noticeably slower writes, fast reads
// Balance is key - only index what you query
// No indexes: Fast writes, slow reads
// With 1 index: Slightly slower writes, fast reads
// With 5 indexes: Noticeably slower writes, fast reads
// Balance is key - only index what you query
// No indexes: Fast writes, slow reads
// With 1 index: Slightly slower writes, fast reads
// With 5 indexes: Noticeably slower writes, fast reads
// Balance is key - only index what you query
// No indexes: Fast writes, slow reads
// With 1 index: Slightly slower writes, fast reads
// With 5 indexes: Noticeably slower writes, fast reads
// Balance is key - only index what you query
Query Performance
Indexes can provide 100-1000x speedup:
- TypeScript
- Java
- Go
- .NET
// Without index: O(n) - scans all nodes
const users = await ductape.graph.findNodes({
labels: ['User'],
where: { email: 'alice@example.com' },
});
// 1M nodes = 1000ms
// With index: O(log n) - uses index
const users = await ductape.graph.findNodes({
labels: ['User'],
where: { email: 'alice@example.com' },
});
// 1M nodes = 1ms
// Without index: O(n) - scans all nodes
Map<String, Object> users = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of( "email", "alice@example.com" )
));
// 1M nodes = 1000ms
// With index: O(log n) - uses index
Map<String, Object> users = ductape.graph.findNodes(Map.of(
labels: ['User'],
where: Map.of( "email", "alice@example.com" )
));
// 1M nodes = 1ms
// Without index: O(n) - scans all nodes
users := client.graph.findNodes({
labels: ['User'],
where: { "email": "alice@example.com" },
});
// 1M nodes = 1000ms
// With index: O(log n) - uses index
users := client.graph.findNodes({
labels: ['User'],
where: { "email": "alice@example.com" },
});
// 1M nodes = 1ms
// Without index: O(n) - scans all nodes
var users = await ductape.graph.findNodes({
labels: ['User'],
where: { ["email"] = "alice@example.com" },
});
// 1M nodes = 1000ms
// With index: O(log n) - uses index
var users = await ductape.graph.findNodes({
labels: ['User'],
where: { ["email"] = "alice@example.com" },
});
// 1M nodes = 1ms
Database-Specific Features
Neo4j
- TypeScript
- Java
- Go
- .NET
// Neo4j supports all index types
await ductape.graph.createNodeIndex({
name: 'idx_user_location',
type: NodeIndexType.POINT,
label: 'User',
properties: ['location'],
});
// Vector indexes (Neo4j 5.11+)
await ductape.graph.createNodeIndex({
name: 'idx_embedding',
type: NodeIndexType.VECTOR,
label: 'Document',
properties: ['embedding'],
options: {
vectorDimensions: 1536,
vectorSimilarityFunction: 'cosine',
},
});
// Neo4j supports all index types
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_location",
type: NodeIndexType.POINT,
"label", "User",
properties: ['location']
));
// Vector indexes (Neo4j 5.11+)
ductape.graph.createNodeIndex(Map.of(
"name", "idx_embedding",
type: NodeIndexType.VECTOR,
"label", "Document",
properties: ['embedding'],
options: Map.of(
"vectorDimensions", 1536,
"vectorSimilarityFunction", "cosine"
)
));
// Neo4j supports all index types
client.graph.createNodeIndex({
"name": "idx_user_location",
type: NodeIndexType.POINT,
"label": "User",
properties: ['location'],
});
// Vector indexes (Neo4j 5.11+)
client.graph.createNodeIndex({
"name": "idx_embedding",
type: NodeIndexType.VECTOR,
"label": "Document",
properties: ['embedding'],
options: {
"vectorDimensions": 1536,
"vectorSimilarityFunction": "cosine",
},
});
// Neo4j supports all index types
await ductape.graph.createNodeIndex({
["name"] = "idx_user_location",
type: NodeIndexType.POINT,
["label"] = "User",
properties: ['location'],
});
// Vector indexes (Neo4j 5.11+)
await ductape.graph.createNodeIndex({
["name"] = "idx_embedding",
type: NodeIndexType.VECTOR,
["label"] = "Document",
properties: ['embedding'],
options: {
["vectorDimensions"] = 1536,
["vectorSimilarityFunction"] = "cosine",
},
});
AWS Neptune
- TypeScript
- Java
- Go
- .NET
// Neptune has limited constraint support
// Focus on indexes for performance
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
});
// Neptune has limited constraint support
// Focus on indexes for performance
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email']
));
// Neptune has limited constraint support
// Focus on indexes for performance
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
});
// Neptune has limited constraint support
// Focus on indexes for performance
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
});
ArangoDB
- TypeScript
- Java
- Go
- .NET
// ArangoDB persistent indexes
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
options: {
sparse: false,
unique: true,
},
});
// ArangoDB persistent indexes
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email'],
options: Map.of(
"sparse", false,
"unique", true
)
));
// ArangoDB persistent indexes
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
options: {
"sparse": false,
"unique": true,
},
});
// ArangoDB persistent indexes
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
options: {
["sparse"] = false,
["unique"] = true,
},
});
Memgraph
- TypeScript
- Java
- Go
- .NET
// Memgraph label-property indexes
await ductape.graph.createNodeIndex({
name: 'idx_user_email',
type: NodeIndexType.BTREE,
label: 'User',
properties: ['email'],
});
// Memgraph label-property indexes
ductape.graph.createNodeIndex(Map.of(
"name", "idx_user_email",
type: NodeIndexType.BTREE,
"label", "User",
properties: ['email']
));
// Memgraph label-property indexes
client.graph.createNodeIndex({
"name": "idx_user_email",
type: NodeIndexType.BTREE,
"label": "User",
properties: ['email'],
});
// Memgraph label-property indexes
await ductape.graph.createNodeIndex({
["name"] = "idx_user_email",
type: NodeIndexType.BTREE,
["label"] = "User",
properties: ['email'],
});
Next Steps
- Query Optimization - Optimize graph queries
- Nodes - Working with graph nodes
- Relationships - Managing relationships
- Traversals - Graph pathfinding
See Also
- Graph Overview - Full API reference
- Best Practices - Performance optimization