Relationships

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

Without relationships, your type definitions represent a collection of disconnected nodes with little value. Adding relationships to your data model gives your data the context that it needs to run complex queries across wide sections of your graph.

This section describes how to model and interact with relationships in your GraphQL schema:

Data model

Take the following graph as an example in which the Person and Movie types are connected by a single relationship type, ACTED_IN. The relationship has a property roles which describes the different roles that an actor played in a movie.

relationship with properties
Figure 1. Model of a Movie node connected to a Person node through a relationship of type ACTED_IN, with a roles property.

Writing type definitions

Nodes

To create the graph using the Neo4j GraphQL Library, first define the two node types together with their fields. In order for these types to be represented as nodes in the graph, decorate them with the @node directive.

Defining the node types
type Person @node {
    name: String!
}

type Movie @node {
    title: String!
    released: Int!
}

Relationships

Define the relationships between the two types by adding special relationship fields using the @relationship directive.

A Person can act in multiple movies, and a Movie can have multiple actors. Conceptually this is a many-to-many relationship and you can model it by using list types for both relationship fields, on both sides of the relationship.

Defining the relationship fields
type Person @node {
    name: String!
    actedInMovies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}

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

Anatomy of a relationship

Relationship direction

The direction argument is relative to the node type on which the @relationship directive is used. The value IN means that the relationship points to this node while OUT means that the relationship originates from this node.

In the example graph, Person-[ACTED_IN]→Movie means that the relationship of type ACTED_IN points to a Movie, therefore the Movie.actors relationship field has direction: IN. Conversely, the Actors.actedInMovies relationship field has direction: OUT because the relationship originates from a Person and points to a Movie.

To figure out whether the direction argument of the @relationship directive should be IN or OUT it can be helpful to visualize your graph like in the diagram above and model the direction of the arrows.

Relationship properties

The ACTED_IN relationship has a property roles which describes the different roles that an actor played in a movie. To model this:

  1. Add an ActedIn type decorated with the @relationshipProperties directive, containing the desired relationship properties.

  2. Set the @relationship directive’s properties argument value to ActedIn. This can be done on both or either side of the relationship, depending on where you want to query the relationship properties from.

Defining relationship properties
type ActedIn @relationshipProperties {
    roles: [String!]
}

type Person @node {
    name: String!
    actedIn: [Movie!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT)
}

type Movie @node {
    title: String!
    released: Int!
    actors: [Person!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN)
}

Relationship properties fields can only be primitive types or their list variants. You cannot have relationship properties of a complex type such as object types or interfaces.