GraphQL one-to-many self-referential relations

This tutorial assumes that you have successfully completed the Dashboard quick start tutorial, and that you still have the Fauna Dashboard open in a browser tab/window. Create a new database before you start the tutorial.

If your Dashboard session has expired:

  1. Log in again.

  2. Select the database.

  3. Click the GRAPHQL button in the left navigation.

To form bi-directional relations in GraphQL requires using the @relation directive, which is explained in the GraphQL relations.

In this tutorial, we explore how to form one-to-many relations from a GraphQL Type to itself. We are using a generic Person Type as an example of modeling parent/child relations. That is, every Person document can have one parent and multiple children relations, where a parent and child are also of the same Person Type. The same can be applied to any use case where one-to-many self-referential relation holds. A common example is an Employee and Manager relation. An Employee can report to one Manager (parent relation), where each Manager is also an Employee and can have relation with multiple other Employees as reports (child relation).

To create such self-referential relations, the relations in GraphQL are modeled using an intermediate "link table" Type.

Tutorial

Let’s first define a simple Person Type, and attempt to make a relation to itself.

  1. Create a new schema file

    Create the file schema-self_ref.graphql with the following content:

    type Person {
      name: String!
      children: [Person]! @relation
    }
  2. Import the GraphQL schema

    1. Click the IMPORT SCHEMA button. If you do not see the button, click the REPLACE SCHEMA button.

    2. In the file dialog, locate and select the file schema-self_ref.graphql, then click the file dialog’s Open button.

    An error message appears: Many to many self-references are not allowed

    The problem is that the GraphQL API does not support applying the dynamically-generated document ID to a document field as a single step, which is required to make a self-referential relation.

    To solve this problem, the schema needs to be adjusted to introduce a Type dedicated to managing the relation.

  3. Modify the schema to create a PersonLink Type to establish a self-referencing one-to-many relation

    Create the file schema-self_ref.graphql with the following content:

    type Person {
      name: String!
      children: [PersonLink]! @relation(name: "person_children")
      parent: PersonLink! @relation(name: "person_parents")
    }
    
    type PersonLink {
      parent: Person! @relation(name: "person_children")
      child: Person! @relation(name: "person_parents") @unique
    }
  4. Replace the schema

    1. Click the REPLACE SCHEMA button.

    2. In the file dialog, locate and select the file schema-self_ref.graphql, then click the file dialog’s Open button.

    This time, the schema import should be successful.

    When the schema is imported, the Fauna GraphQL API creates collections named Person and PersonLink. It specifies that a Person document has exactly one parent document. This means that there can only ever be one relation to a Person as a child. The schema also specifies than a Person can have a list of children, so that one Person document can be related to many child Person documents.

  5. Create a Person and its parent-child relations

    Now that you have the new schema in place, to create relations between the parent/child persons, you have to create the "links".

    1. Copy the following GraphQL mutation, which creates a Person document named Person1, plus its children documents Child1 and Child2:

      mutation{
        createPerson(data: {
          name: "Person1",
          children: {
            create: [
              { child: {create: {name: "child1"}}},
              { child: {create: {name: "child2"}}},
            ]
          }
        })
        {
          _id
          name
          children {
            data {
              _id
              child {
                _id
                name
              }
            }
          }
        }
      }
    2. Click the "new tab" + button in the GraphQL Playground screen in your browser (at the top left, just right of the last query tab).

    3. Paste the query into the left panel, and click the "Play" button.

    The query should execute and it should create a list of PersonLink documents, each one creating a Person as a child and a Person as a parent. The response should appear in the panel on the right:

    {
      "data": {
        "createPerson": {
          "_id": "335202398647616000",
          "name": "Person1",
          "children": {
            "data": [
              {
                "_id": "335202398657054208",
                "child": {
                  "_id": "335202398657053184",
                  "name": "child1"
                }
              },
              {
                "_id": "335202398658102784",
                "child": {
                  "_id": "335202398658101760",
                  "name": "child2"
                }
              }
            ]
          }
        }
      }
    }

    Alternately, you can create Person documents and then create a link to connect parent and child as shown in the Many-to-many self-referential relations tutorial.

  6. Query all children relations of a person

    Now that the parent/child relations are in place, let’s verify that for a person.

    1. Copy the following GraphQL query:

      query FindChildren {
        findPersonByID(id:"<$PERSON_ID>") {
          name
          children{
            data {
              child {
                name
              }
            }
          }
        }
      }
    2. Click the "new tab" + button in the GraphQL Playground screen in your browser (at the top left, just right of the last query tab).

    3. Paste the query into the left panel

    4. Replace the string <$PERSON_ID> with the value of the _id field, immediately following the createPerson field, from the previous step’s response.

    5. Click the "Play" button.

    The response, in the right-hand panel, should be similar to:

    {
      "data": {
        "findPersonByID": {
          "name": "Person1",
          "children": {
            "data": [
              {
                "child": {
                  "name": "child1"
                }
              },
              {
                "child": {
                  "name": "child2"
                }
              }
            ]
          }
        }
      }
    }

Conclusion

This tutorial has demonstrated how to setup GraphQL one-to-many self-referential relations.

For more information on GraphQL relations, see Relations.

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!