website/src/docs/hotchocolate/v12/integrations/neo4j.md
HotChocolate has a data integration for Neo4J. With this integration, you can translate paging, filtering, sorting, and projections, directly into native cypher queries.
You can find an example project in HotChocolate Examples
To use the Neo4J integration, you need to install the package HotChocolate.Data.Neo4J.
The whole integration builds around IExecutable<T>.
The execution engine picks up the IExecutable and executes it efficiently.
[UseNeo4JDatabase("neo4j")]
[UsePaging]
[UseProjection]
[UseSorting]
[UseFiltering]
public IExecutable<Person> GetPersons([ScopedService] IAsyncSession session) => new Neo4JExecutable<Person>(session);
To use Neo4J filtering you need to register the convention on the schema builder:
services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddNeo4JFiltering();
To use Neo4J filtering alongside with
IQueryable/IEnumerable, you have to register the Neo4J convention under a different scope. You can specify the scope on the schema builder by executingAddNeo4JFiltering("yourScope"). You then have to specify this scope on each method you use Neo4J filtering:[UseFiltering(Scope = "yourScope")]orUseFiltering(scope = "yourScope")
Your filters are now converted to cypher and applied to the executable.
GraphQL Query:
query GetPersons {
persons(
where: {
name: { eq: "Yorker Shorton" }
addresses: { some: { street: { eq: "04 Leroy Trail" } } }
}
) {
name
addresses {
street
city
}
}
}
Cypher Query
MATCH (person:Person)
WHERE person.name = 'Yorker Shorton" AND
RETURN person {.name}
To use Neo4J sorting you need to register the convention on the schema builder:
services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddNeo4JSorting();
To use Neo4J Sorting alongside with
IQueryable/IEnumerable, you have to register the Neo4J convention under a different scope. You can specify the scope on the schema builder by executingAddNeo4JSorting("yourScope"). You then have to specify this scope on each method you use Neo4J Sorting:[UseSorting(Scope = "yourScope")]orUseSorting(scope = "yourScope")
Your sorting is now converted to cypher and applied to the executable.
GraphQL Query:
query GetPersons {
persons(order: [{ name: ASC }]) {
name
addresses {
street
city
}
}
}
Cypher Query
MATCH (person:Person)
WHERE person.name = 'Yorker Shorton" AND
RETURN person {.name}
To use Neo4J projections you need to register the convention on the schema builder:
services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddNeo4JProjections();
To use Neo4J Projections alongside with
IQueryable/IEnumerable, you have to register the Neo4J convention under a different scope. You can specify the scope on the schema builder by executingAddNeo4JProjections("yourScope"). You then have to specify this scope on each method you use Neo4J Projections:[UseProjections(Scope = "yourScope")]orUseProjections(scope = "yourScope")
GraphQL Query:
query GetPersons {
persons {
name
addresses {
city
}
}
}
Cypher Query
MATCH (person:Person)
WHERE person.name = 'Yorker Shorton" AND
RETURN person {.name}
In order to use pagination with Neo4J, we have to register the Neo4J specific pagination providers.
services
.AddGraphQLServer()
.AddNeo4JPagingProviders();
Learn more about pagination providers
To use cursor based pagination annotate you resolver with [UseNeo4JPaging] or .UseNeo4JPaging()
[UseNeo4JDatabase("neo4j")]
[UsePaging]
[UseProjection]
public IExecutable<Person> GetPersons([ScopedService] IAsyncSession session) => new Neo4JExecutable<Person>(session);
You can then execute queries like the following one:
query GetPersons {
persons(first: 50, after: "OTk=") {
nodes {
name
addresses {
city
}
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
}
To use cursor based pagination annotate you resolver with [UseNeo4JPaging] or .UseNeo4JPaging()
[UseNeo4JDatabase("neo4j")]
[UseOffsetPaging]
[UseProjection]
public IExecutable<Person> GetPersons([ScopedService] IAsyncSession session) => new Neo4JExecutable<Person>(session);
You can then execute queries like the following one:
query GetPersons {
persons(skip: 50, take: 50) {
items {
name
addresses {
city
}
}
pageInfo {
hasNextPage
hasPreviousPage
}
}
}