CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-neo4j-driver

The official Neo4j driver for JavaScript applications, enabling connection to and interaction with Neo4j graph databases.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

transaction-management.mddocs/

Transaction Management

Transaction handling including explicit transactions and managed transactions with automatic retry logic for robust database operations.

Capabilities

Explicit Transaction Control

Manual transaction management with full control over commit and rollback operations.

interface Transaction {
  /**
   * Run a Cypher query within the transaction
   * @param query - The Cypher query string
   * @param parameters - Query parameters as key-value pairs
   * @returns Promise resolving to query result
   */
  run(query: string, parameters?: Parameters): Promise<Result>;
  
  /** Commit the transaction and make changes permanent */
  commit(): Promise<void>;
  
  /** Rollback the transaction and discard changes */
  rollback(): Promise<void>;
  
  /** Check if the transaction is still open and active */
  isOpen(): boolean;
}

Usage Examples:

const session = neo4jDriver.session();

// Basic transaction usage
const tx = await session.beginTransaction();
try {
  const result = await tx.run(
    "CREATE (p:Person {name: $name}) RETURN p",
    { name: "Alice" }
  );
  
  await tx.commit();
  console.log("Transaction committed");
} catch (error) {
  await tx.rollback();
  console.error("Transaction rolled back:", error);
} finally {
  await session.close();
}

// Complex multi-step transaction
const complexTx = await session.beginTransaction({
  timeout: 60000, // 1 minute timeout
  metadata: { operation: "user_registration" }
});

try {
  // Step 1: Create user
  const userResult = await complexTx.run(`
    CREATE (u:User {id: randomUUID(), email: $email, createdAt: datetime()})
    RETURN u.id AS userId
  `, { email: "user@example.com" });
  
  const userId = userResult.records[0].get("userId");
  
  // Step 2: Create user profile
  await complexTx.run(`
    MATCH (u:User {id: $userId})
    CREATE (u)-[:HAS_PROFILE]->(p:Profile {
      firstName: $firstName,
      lastName: $lastName,
      updatedAt: datetime()
    })
  `, {
    userId,
    firstName: "John",
    lastName: "Doe"
  });
  
  // Step 3: Add to default groups
  await complexTx.run(`
    MATCH (u:User {id: $userId}), (g:Group {name: 'users'})
    CREATE (u)-[:MEMBER_OF]->(g)
  `, { userId });
  
  await complexTx.commit();
  console.log(`User ${userId} registered successfully`);
} catch (error) {
  await complexTx.rollback();
  console.error("User registration failed:", error);
} finally {
  await session.close();
}

Managed Transactions

Managed transactions with automatic retry logic and simplified error handling.

interface ManagedTransaction {
  /**
   * Run a Cypher query within the managed transaction
   * @param query - The Cypher query string
   * @param parameters - Query parameters as key-value pairs
   * @returns Promise resolving to query result
   */
  run(query: string, parameters?: Parameters): Promise<Result>;
}

interface Session {
  /**
   * Execute a read transaction with automatic retry logic
   * @param work - Function containing read operations
   * @param config - Optional transaction configuration
   * @returns Promise resolving to the work function result
   */
  executeRead<T>(
    work: (tx: ManagedTransaction) => Promise<T>,
    config?: TransactionConfig
  ): Promise<T>;
  
  /**
   * Execute a write transaction with automatic retry logic
   * @param work - Function containing write operations
   * @param config - Optional transaction configuration
   * @returns Promise resolving to the work function result
   */
  executeWrite<T>(
    work: (tx: ManagedTransaction) => Promise<T>,
    config?: TransactionConfig
  ): Promise<T>;
}

Usage Examples:

const session = neo4jDriver.session();

try {
  // Read transaction - automatically retried on failure
  const users = await session.executeRead(async tx => {
    const result = await tx.run(`
      MATCH (u:User)-[:HAS_PROFILE]->(p:Profile)
      WHERE u.createdAt > datetime({year: 2023})
      RETURN u.email, p.firstName, p.lastName
      ORDER BY u.createdAt DESC
      LIMIT 100
    `);
    
    return result.records.map(record => ({
      email: record.get("u.email"),
      firstName: record.get("p.firstName"),
      lastName: record.get("p.lastName")
    }));
  });
  
  console.log(`Found ${users.length} recent users`);
  
  // Write transaction with retry logic
  const orderId = await session.executeWrite(async tx => {
    // Create order
    const orderResult = await tx.run(`
      CREATE (o:Order {
        id: randomUUID(),
        status: 'pending',
        createdAt: datetime(),
        total: $total
      })
      RETURN o.id AS orderId
    `, { total: 99.99 });
    
    const id = orderResult.records[0].get("orderId");
    
    // Add order items
    await tx.run(`
      MATCH (o:Order {id: $orderId})
      UNWIND $items AS item
      CREATE (o)-[:CONTAINS]->(oi:OrderItem {
        productId: item.productId,
        quantity: item.quantity,
        price: item.price
      })
    `, {
      orderId: id,
      items: [
        { productId: "prod-123", quantity: 2, price: 49.99 },
        { productId: "prod-456", quantity: 1, price: 0.01 } // Tax adjustment
      ]
    });
    
    return id;
  }, {
    timeout: 30000,
    metadata: { operation: "create_order", version: "v2" }
  });
  
  console.log(`Created order: ${orderId}`);
} finally {
  await session.close();
}

Transaction Configuration

Configuration options for controlling transaction behavior.

interface TransactionConfig {
  /** Transaction timeout in milliseconds */
  timeout?: number;
  
  /** 
   * Transaction metadata for monitoring and debugging
   * Useful for tracking operations in Neo4j logs
   */
  metadata?: Record<string, any>;
}

Usage Examples:

// Long-running transaction with custom timeout
await session.executeWrite(async tx => {
  // Bulk data import operation
  const result = await tx.run(`
    LOAD CSV WITH HEADERS FROM $csvUrl AS row
    CREATE (p:Product {
      id: row.id,
      name: row.name,
      price: toFloat(row.price),
      category: row.category,
      importedAt: datetime()
    })
  `, { csvUrl: "file:///import/products.csv" });
  
  return result.summary.counters.nodesCreated;
}, {
  timeout: 300000, // 5 minutes for large import
  metadata: {
    operation: "bulk_import",
    source: "products.csv",
    batchId: "batch-001"
  }
});

// Transaction with detailed metadata
await session.executeWrite(async tx => {
  await tx.run(`
    MATCH (u:User {id: $userId})
    SET u.lastLogin = datetime(),
        u.loginCount = coalesce(u.loginCount, 0) + 1
  `, { userId: "user-123" });
}, {
  metadata: {
    operation: "user_login",
    userId: "user-123",
    timestamp: new Date().toISOString(),
    source: "web_app"
  }
});

Transaction Best Practices

Retry Logic: Managed transactions automatically retry on transient errors like connection issues or deadlocks. The driver uses exponential backoff and respects cluster topology changes.

Read vs Write Transactions:

  • Use executeRead for queries that only read data
  • Use executeWrite for queries that modify data
  • This enables proper routing in cluster environments

Transaction Size:

  • Keep transactions small and focused
  • Avoid long-running transactions that hold locks
  • Consider breaking large operations into smaller transactions

Error Handling:

  • Managed transactions handle retryable errors automatically
  • Non-retryable errors (like constraint violations) are thrown immediately
  • Always handle business logic errors in your work function

Performance Tips:

  • Use parameters instead of string concatenation
  • Batch related operations in single transactions
  • Use UNWIND for bulk operations
  • Profile queries to optimize performance
// Good: Focused transaction
await session.executeWrite(async tx => {
  await tx.run(`
    MATCH (u:User {id: $userId})
    SET u.status = $status, u.updatedAt = datetime()
  `, { userId, status: "active" });
});

// Good: Bulk operation with UNWIND
await session.executeWrite(async tx => {
  await tx.run(`
    UNWIND $users AS user
    MERGE (u:User {id: user.id})
    SET u.email = user.email, u.updatedAt = datetime()
  `, { users: userBatch });
});

// Avoid: Transaction too large
await session.executeWrite(async tx => {
  // Too many operations in single transaction
  for (const user of allUsers) { // Could be thousands
    await tx.run("CREATE (u:User $props)", { props: user });
  }
});

docs

authentication.md

driver-management.md

error-handling.md

graph-types.md

index.md

reactive-programming.md

session-operations.md

temporal-types.md

transaction-management.md

tile.json