Neo4j
ETLBox supports integration with Neo4j, a graph database designed to store connected data using nodes and relationships.
The ETLBox connector allows you to:
- Read data from Neo4j using Cypher queries (
Neo4jSource
) - Write nodes and relationships to Neo4j using custom Cypher commands (
Neo4jDestination
)
You can map Neo4j records to POCOs or use ExpandoObject
for dynamic structures.
Neo4jSource
Neo4jSource<T>
reads records from a Neo4j database using a user-defined Cypher query and deserializes them into objects of type T
.
Basic Usage
To query all movies and read their names:
public class MovieRow {
public string Name { get; set; }
}
var source = new Neo4jSource<MovieRow> {
ConnectionString = "bolt://localhost:7687",
Cypher = "MATCH (m:Movie) RETURN m.name AS Name"
};
var dest = new MemoryDestination<MovieRow>();
source.LinkTo(dest);
Network.Execute(source);
In this case, each row returned by the query must have a field name
, which maps to the Name
property of the MovieRow
class.
Querying Relationships
If you want to extract relationship information:
public class MovieActorRelation {
public string Movie { get; set; }
public string Actor { get; set; }
}
var source = new Neo4jSource<MovieActorRelation> {
ConnectionString = "bolt://localhost:7687",
Cypher = @"
MATCH (m:Movie)-[:ACTED_IN]-(a:Actor)
RETURN m.name AS Movie, a.name AS Actor"
};
This fetches actor names and the movies they acted in, and maps the result into the MovieActorRelation
POCO.
Dynamic Object Support
If the graph structure or output fields are not fixed, you can use dynamic objects (ExpandoObject
) with Neo4jSource
:
var source = new Neo4jSource {
ConnectionString = "bolt://localhost:7687",
Cypher = "MATCH (n:Movie) RETURN n.name AS Title"
};
var dest = new MemoryDestination();
source.LinkTo(dest);
Network.Execute(source);
foreach (dynamic row in dest.Data) {
Console.WriteLine(row.Title);
}
Shared Configuration
Both source and destination components support the following shared configuration:
Connection Properties
ConnectionString
: The Neo4j Bolt protocol URI (e.g.,bolt://localhost:7687
)Driver
: Optional instance ofIDriver
from the Neo4j.Driver package. If provided, this driver will be reused instead of creating a new one.Session
: OptionalIAsyncSession
. If supplied, the session is reused for query execution. Use this when integrating with transactions or managing sessions externally.
Example: Using an Existing Session
var driver = GraphDatabase.Driver("bolt://localhost:7687", AuthTokens.Basic("neo4j", "password"));
var session = driver.AsyncSession();
var source = new Neo4jSource<MovieRow> {
Session = session,
Cypher = "MATCH (m:Movie) RETURN m.name AS Name"
};
Neo4jDestination
The Neo4jDestination<T>
component allows you to persist object data into a Neo4j graph using Cypher commands. You define the Cypher statements via a delegate function.
Limited Graph Mapping Support
The Neo4jDestination
provides only basic write support. Due to the fundamental differences between row-based data and graph models, automatic mapping of rows to complex graph structures is not supported. You must write explicit Cypher queries to control how nodes and relationships are created.
Basic Usage
public class Movie {
public string Name { get; set; }
public string Genre { get; set; }
}
var source = new MemorySource<Movie>();
source.Data = new List<Movie> {
new Movie { Name = "The Matrix", Genre = "Sci-Fi" },
new Movie { Name = "Inception", Genre = "Thriller" }
};
var dest = new Neo4jDestination<Movie> {
ConnectionString = "bolt://localhost:7687",
CreateCypherFunc = (movie, suggestion) =>
$@"CREATE (m:Movie {{name: '{movie.Name}', genre: '{movie.Genre}'}})"
};
source.LinkTo(dest);
Network.Execute(source);
This inserts two movie nodes into the database.
Using CreateCypherFunc
The CreateCypherFunc
has the following signature:
Func<T, string, string>
- The first parameter is the current row.
- The second parameter (
cypherSuggestion
) is a pre-filled Cypher fragment generated based on object properties.
You can use this to conditionally build logic, define relationships, or modify node labels dynamically.
Example: Writing Nodes and Relationships
public class Movie {
public string Title { get; set; }
public Person[] Actors { get; set; }
}
public class Person {
public string Name { get; set; }
}
var source = new MemorySource<Movie>();
source.Data = new List<Movie> {
new Movie {
Title = "Interstellar",
Actors = new[] {
new Person { Name = "Matthew McConaughey" },
new Person { Name = "Anne Hathaway" }
}
}
};
var dest = new Neo4jDestination<Movie> {
ConnectionString = "bolt://localhost:7687",
CreateCypherFunc = (movie, _) => {
var actorCreates = string.Join("\n", movie.Actors.Select((a, i) =>
$"MERGE (a{i}:Person {{name: '{a.Name}'}})\n" +
$"MERGE (m)-[:ACTED_IN]->(a{i})"));
return
$@"MERGE (m:Movie {{title: '{movie.Title}'}})
{actorCreates}";
}
};
source.LinkTo(dest);
Network.Execute(source);
This creates movie nodes and related actor nodes, connecting them with ACTED_IN
relationships.