Data types and mapping to Cypher types
The tables in this section show the mapping between Cypher data types and .NET types.
Core types
| Cypher type | Driver type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Temporal types
The driver provides a set of temporal data types compliant with ISO-8601 and Cypher.
Sub-second values are measured to nanosecond precision.
Time zone names adhere to the IANA system, rather than the Windows system.
Inbound conversion is carried out using Extended Windows-Olson zid mapping as defined by Unicode CLDR.
| Cypher type | Driver type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
// Define a date, with timezone, and use it to set a relationship property
var friendsSince = new ZonedDateTime(new DateTime(2016, 12, 16, 13, 59, 59, 999), "Europe/Stockholm");
var result = await driver.ExecutableQuery(@"
MERGE (a:Person {name: $name})
MERGE (b:Person {name: $friend})
MERGE (a)-[friendship:KNOWS {since: $friendsSince}]->(b)
RETURN friendship.since AS date
")
.WithParameters(new { name = "Astrid", friend = "Sara", friendsSince = friendsSince })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
Console.WriteLine(result.Result[0].Get<ZonedDateTime>("date"));
// 2016-12-16T13:59:59.999000000[Europe/Stockholm]
Spatial types
Cypher supports spatial values (points), and Neo4j can store these point values as properties on nodes and relationships.
The attribute SRID (short for Spatial Reference Identifier) is a number identifying the coordinate system the spatial type is to be interpreted in.
You can think of it as a unique identifier for each spatial type.
| Cypher type | Driver type | SRID |
|---|---|---|
|
7203 |
|
|
4326 |
|
|
9157 |
|
|
4979 |
Point value from the databasevar result = await driver.ExecutableQuery("RETURN point({x: 2.3, y: 4.5, z: 2}) AS point")
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
Console.WriteLine(result.Result[0].Get<Point>("point"));
// Point{srId=9157, x=2.3, y=4.5, z=2}
Point value and use it as property valuevar location = new Point(4326, 67.28775180193841, 17.734163823312397); // 4326 = 2D geodetic point
var result = await driver.ExecutableQuery("CREATE (p:PlaceOfInterest {location: $location}) RETURN p")
.WithParameters(new { location = location })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
Console.WriteLine(result.Result[0].Get<INode>("p").Get<Point>("location"));
// Point{srId=4326, x=67.28775180193841, y=17.734163823312397}
Graph types
Graph types are only passed as results and may not be used as parameters.
| Cypher Type | Driver type |
|---|---|
|
|
|
|
|
INode
Represents a node in a graph.
| Property/Method | Return |
|---|---|
|
Node labels, as a list. |
|
Node properties, as a map. |
|
Value for the given property, casted to |
|
String identifier for the node.
This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. In other words, using an |
var result = await driver.ExecutableQuery("MERGE (p:Person:Troublemaker {name: $name, age: $age}) RETURN p")
.WithParameters(new { name = "Carla", age = 59 })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
var node = result.Result[0].Get<INode>("p");
Console.WriteLine("Labels: {0}", string.Join(", ", node.Labels));
Console.WriteLine("Properties: {0}", string.Join(", ", node.Properties));
Console.WriteLine("Name property: {0}", node.Get<string>("name"));
/*
Labels: Person, Troublemaker
Properties: [name, Carla], [age, 59]
Name property: Carla
*/
For full documentation, see API documentation → INode.
IRelationship
Represents a relationship in a graph.
| Property/Method | Return |
|---|---|
|
Relationship type. |
|
Relationship properties, as a map. |
|
Value for the given property, casted to |
|
|
|
|
|
String identifier for the relationship.
This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. In other words, using an |
var result = await driver.ExecutableQuery(@"
MERGE (p:Person {name: $name})
MERGE (friend:Person {name: $friendName})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend)
RETURN r AS friendship
")
.WithParameters(new { name = "Alice", friendName = "Bob", status = "BFF" })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
var relationship = result.Result[0].Get<IRelationship>("friendship");
Console.WriteLine($"Type: {relationship.Type}");
Console.WriteLine("Properties: {0}", string.Join(", ", relationship.Properties));
Console.WriteLine("Status property: {0}", relationship.Get<string>("status"));
/*
Type: KNOWS
Properties: [since, 2024-12-22], [status, BFF]
Status property: BFF
*/
For full documentation, see API documentation → IRelationship.
IPath
Represents a path in a graph.
using Neo4j.Driver;
const string dbUri = "<database-uri>";
const string dbUser = "<username>";
const string dbPassword = "<password>";
await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Basic(dbUser, dbPassword));
await driver.VerifyConnectivityAsync();
// Create some :Person nodes linked by :KNOWS relationships
await addFriend(driver, "Alice", "BFF", "Bob");
await addFriend(driver, "Bob", "Fiends", "Sofia");
await addFriend(driver, "Sofia", "Acquaintances", "Alice");
// Follow :KNOWS relationships outgoing from Alice three times, return as path
var result = await driver.ExecutableQuery(@"
MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
RETURN path AS friendshipChain
")
.WithParameters(new { name = "Alice" })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
// Extract path from result
var path = result.Result[0].Get<IPath>("friendshipChain");
Console.WriteLine("-- Path breakdown --");
for (var i=0; i<path.Relationships.Count; i++) {
Console.WriteLine("{0} knows {1} ({2}).",
path.Nodes[i].Get<string>("name"),
path.Nodes[i+1].Get<string>("name"),
path.Relationships[i].Get<string>("status")
);
}
/*
-- Path breakdown --
Alice knows Bob (BFF).
Bob knows Sofia (Fiends).
Sofia knows Sofia (Acquaintances).
*/
async Task addFriend(IDriver driver, string name, string status, string friendName) {
await driver.ExecutableQuery(@"
MERGE (p:Person {name: $name})
MERGE (friend:Person {name: $friendName})
MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend)
")
.WithParameters(new { name = name, status = status, friendName = friendName })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
}
For full documentation, see API documentation → IPath.
VectorIntroduced in 6.0
The type Vector maps to the Cypher type VECTOR.
Vector objects are stored as contiguous blocks of memory, containing homogeneous values.
You can create vectors from lists of float, double, sbyte, short, int, long.
Storing VECTOR objects in the database requires a server version >= 2025.10, Enterprise Edition.
|
var vector = new Vector<int>([5, 6, 7]);
var result = await driver.ExecutableQuery("MERGE (d:Doc {embedding: $vector})")
.WithParameters(new { vector = vector })
.WithConfig(new QueryConfig(database: "<database-name>"))
.ExecuteAsync();
UnsupportedTypeIntroduced in 6.0
The type UnsupportedType is used for data types returned by Cypher queries that the driver doesn’t recognize.
This happens when the client version is too old with respect to the server version.
Glossary
- LTS
-
A Long Term Support release is one guaranteed to be supported for a number of years. Neo4j 4.4 and 5.26 are LTS versions.
- Aura
-
Aura is Neo4j’s fully managed cloud service. It comes with both free and paid plans.
- Cypher
-
Cypher is Neo4j’s graph query language that lets you retrieve data from the database. It is like SQL, but for graphs.
- APOC
-
Awesome Procedures On Cypher (APOC) is a library of (many) functions that can not be easily expressed in Cypher itself.
- Bolt
-
Bolt is the protocol used for interaction between Neo4j instances and drivers. It listens on port 7687 by default.
- ACID
-
Atomicity, Consistency, Isolation, Durability (ACID) are properties guaranteeing that database transactions are processed reliably. An ACID-compliant DBMS ensures that the data in the database remains accurate and consistent despite failures.
- eventual consistency
-
A database is eventually consistent if it provides the guarantee that all cluster members will, at some point in time, store the latest version of the data.
- causal consistency
-
A database is causally consistent if read and write queries are seen by every member of the cluster in the same order. This is stronger than eventual consistency.
- NULL
-
The null marker is not a type but a placeholder for absence of value. For more information, see Cypher → Working with
null. - transaction
-
A transaction is a unit of work that is either committed in its entirety or rolled back on failure. An example is a bank transfer: it involves multiple steps, but they must all succeed or be reverted, to avoid money being subtracted from one account but not added to the other.
- backpressure
-
Backpressure is a force opposing the flow of data. It ensures that the client is not being overwhelmed by data faster than it can handle.
- bookmark
-
A bookmark is a token representing some state of the database. By passing one or multiple bookmarks along with a query, the server will make sure that the query does not get executed before the represented state(s) have been established.
- transaction function
-
A transaction function is a callback executed by an
.ExecuteReadAsync()or.ExecuteWriteAsync()call. The driver automatically re-executes the callback in case of server failure. - IDriver
-
A
IDriverobject holds the details required to establish connections with a Neo4j database.