Database mapping
This page describes how to use directives for database mapping. Each type in your GraphQL type definitions can be mapped to an entity in your Neo4j database, such as nodes, relationships, and relationship properties.
@relationship
Relationships are represented by marking particular fields with a directive — in this case, @relationship
.
It defines the relationship type in the database, as well as which direction that relationship goes in.
To add a second node type, "Actor", and connect the two together, you should do the following:
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}
type Actor {
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
Note that, in this case, there is a directive on each "end" of the relationship, but it is not essential.
@relationshipProperties
Definition
"""Required to differentiate between interfaces for relationship properties, and otherwise."""
directive @relationshipProperties on OBJECT
@relationshipProperties
can only be used on interfaces.
Usage
In order to add properties to a relationship, add a new type to your type definitions decorated with the @relationshipProperties
directive.
For example, for the "ACTED_IN" relationship, add a property "roles":
type Movie {
title: String
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}
type Actor {
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn")
}
type ActedIn @relationshipProperties {
roles: [String]
}
Note that in addition to this type, there is an added key properties
in the existing @relationship
directives.
For more information, see Type definitions → Relationships.
@node
The most basic mapping uses GraphQL type names to map to a Neo4j node label. For example, to represent a node with the label "Movie" and a single property "title" of type string:
type Movie {
title: String
}
With the @node
directive, you have more control over this mapping, and you can specify the configuration of a GraphQL object type which represents a Neo4j node.
It can be appended with the following optional parameters:
labels
This parameter defines the list of label to be used in Neo4j instead of the GraphQL type name:
type Dog @node(labels: ["K9"]) {
name: String!
}
This way, the following query:
{
dogs {
name
}
}
Generates the Cypher query:
MATCH (this: K9)
RETURN this { .name } as name
If the GraphQL type name should still be used as a label, it needs to be specified as well:
type Dog @node(labels: ["Dog", "K9"]) {
name: String!
}
This way, the following query:
{
dogs {
name
}
}
Generates the Cypher query:
MATCH (this:Dog:K9)
RETURN this { .name } as this
Defining |
The following example results in a unique constraint to be asserted for the label K9
and the property name
:
type Dog @node(labels: ["K9", "Dog"]) {
name: String! @unique
}
Using $jwt
and $context
In some cases, you may want to generate dynamic labels depending on the user requesting.
For that, you can use the variable $jwt
to define a custom label in the JWT:
type User @node(labels: ["$jwt.username"]) {
name: String!
}
The following query yields a different Cypher query depending on the user JWT:
{
users {
name
}
}
Assuming there is a user with the value "username": "arthur"
in JWT, the Cypher query looks like:
MATCH (this:arthur)
RETURN this { .name } as this
Similarly, context values can be passed directly:
type User @node(label: ["$context.appId"]) {
name: String!
}
When running the server with Apollo:
const server = new ApolloServer({
schema: await neoSchema.getSchema(),
});
await startStandaloneServer(server, {
context: async ({ req }) => ({ req, appId: "myApp" }),
});
@alias
This directive maps a GraphQL field to a Neo4j property on a node or relationship.
It can be used on any fields that are not @cypher
or @relationship
fields.
For example:
type User {
id: ID! @id @alias(property: "dbId")
username: String!
}
type User {
id: ID! @id
username: String! @alias(property: "dbUserName")
livesIn: [City!]! @relationship(direction: OUT, type: "LIVES_IN", properties: "UserLivesInProperties")
}
type City {
name: String
}
type UserLivesInProperties @relationshipProperties {
since: DateTime @alias(property: "moveInDate")
}
The property in aliases are automatically escaped (wrapped with backticks ``), so there is no need to add escape characters around them. |