Database mapping

This is the documentation of the GraphQL Library version 6. For the long-term support (LTS) version 5, refer to GraphQL Library version 5 LTS.

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.

@node

Definition

"""Informs @neo4j/graphql of node metadata"""
directive @node(
  """The labels to map this GraphQL type to in the Neo4j database"""
  labels: [String!]
) on OBJECT

Usage

Adding the @node directive to your GraphQL type specifies that it represents a Neo4j node. For example, to represent a Neo4j node with the label "Movie" and a single property "title" of type string:

type Movie @node {
    title: String
}

In version 6.x, it’s not required to specify every GraphQL type representing a Neo4j node with the @node directive. In the future, types without the @node directive will no longer be treated as Neo4j nodes.

When not differently specified, the GraphQL type name is used as a label for the represented Neo4j node. It’s possible to explicitly define the Neo4j node labels by using the parameter labels.

The labels parameter

You can append the optional parameters labels to a GraphQL object with the @node directive. This parameter lists the labels to be used in Neo4j instead of the GraphQL type name.

Example 1. Querying a field with the labels parameter

Consider the following type definition:

type Dog @node(labels: ["K9"]) {
    name: String!
}

Here is a query against the Dog node:

{
  dogs {
    name
  }
}

The following Cypher is generated:

MATCH (this: K9)
RETURN this { .name } as name

If you want to use the GraphQL type name as a label, specifiy both.

Example 2. Querying a field with two entries for the labels parameter

Consider the following type definition:

type Dog @node(labels: ["Dog", "K9"]) {
    name: String!
}

Here is an example for a query against the Dog node

{
  dogs {
    name
  }
}

The following Cypher is generated:

MATCH (this:Dog:K9)
RETURN this { .name } as this

Defining labels means you take control of the database labels of the node. Indexes and constraints in Neo4j only support a single label, for which the first element of the labels argument is used.

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
}

See @unique to learn more about the @unique directive.

Using $jwt and $context

In some cases, you may want to generate dynamic labels depending on the user requesting. You can use the variable $jwt to define a custom label in the JWT.

Example 3. Querying a field with a $jwt variable in the labels parameter

Consider the following type definition:

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 this:

MATCH (this:arthur)
RETURN this { .name } as this

Similarly, context values can be passed directly:

type User @node(label: ["$context.appId"]) {
    name: String!
}

For example, if you are running the server with Apollo:

const server = new ApolloServer({
    schema: await neoSchema.getSchema(),
});

await startStandaloneServer(server, {
    context: async ({ req }) => ({ req, appId: "myApp" }),
});

@relationship

Definition

"""
Instructs @neo4j/graphql to treat this field as a relationship. Opens up the ability to create and connect on this field.
"""
directive @relationship(
  type: String!
  """Valid and default directions for this relationship."""
  queryDirection: RelationshipQueryDirection = DEFAULT_DIRECTED
  direction: RelationshipDirection!
  """
  The name of the interface containing the properties for this relationship.
  """
  properties: String
  """
  Prevent all but these operations from being generated for this relationship
  """
  nestedOperations: [RelationshipNestedOperations!]! = [CREATE, UPDATE, DELETE, CONNECT, DISCONNECT, CONNECT_OR_CREATE]
  """Prevent aggregation for this relationship"""
  aggregate: Boolean = true
) on FIELD_DEFINITION

Usage

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 two node types, "Movie" and "Actor", and connect the two:

type Movie {
    title: String
    actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}

type Actor {
    name: String
    movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}

The @relationship directive is used twice, once on each end of the relationship. This is the standard way of modeling a relationship with the GraphQL Library. However, it is not a requirement of the type definitions themselves as relationships can deliberately be underspecified, for example to limit access through the API layer.

@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.

@alias

Definition

"""
Instructs @neo4j/graphql to map a GraphQL field to a Neo4j node or relationship property.
"""
directive @alias(
  """The name of the Neo4j property"""
  property: String!
) on FIELD_DEFINITION

Usage

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 @node {
    id: ID! @id @alias(property: "dbId")
    username: String!
}
type User @node {
    id: ID! @id
    username: String! @alias(property: "dbUserName")
    livesIn: [City!]! @relationship(direction: OUT, type: "LIVES_IN", properties: "UserLivesInProperties")
}

type City @node {
    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.