Dgraph GraphQL Tour
Schema
Reverse edges
In Dgraph, edges are directional. A query can’t traverse an edge in reverse. Fundamentally, there are two options for querying in both directions:
- Add the reverse edge to the schema and then add all the reverse edge data.
- Tell Dgraph to always store the reverse edge using the
@reverse
keyword in the DQL schema. (Not available in the GraphQL schema)
In the generated GraphQL API, Dgraph provides support for the first option with
easy-to-use directives. Normally a user would have to define two-way edges by
creating two edges for each desired bidirectional edge. In the GraphQL schema, a
user can alternatively provide the @hasInverse
directive and the generated
GraphQL API will ensure that all relationships created or removed from within
the API are balanced. This directive only needs to be applied to one end of the
two-way relationship, but it helps schema readability if this directive is applied
on both ends of the relationship. @hasInverse
does the same thing whether it
is applied on one side, the other side, or both sides of the two-way edge
relationship.
You have already seen this directive in action. In the schema provided in the
previous lessons, you applied this @hasInverse
directive between the following
relationships:
Person.friends
<->Person.friends
Person.ownsPets
<->Animal.owner
Person.employers
<->Company.employees
Person.manages
<->Person.manager
When applying the @hasInverse
directive, it is required to define the field on
the opposite side of the edge.
Here is an example of an very simple schema that uses the @hasInverse
directive to create a bidirectional edge between Person.employers
and
Company.employees
:
type Company {
employees: [Person] @hasInverse(field: "employers")
}
type Person {
employers: [Company]
}
You can define a variety of different types of relationships between types in
your schema using bidirectional edges: one-to-one (1:1
), one-to-many (1:n
), and
many-to-many (n:n
).
To define a 1:1
relationship, do not include the list brackets on either side
of the relationship. This will ensure that one node only ever points to at most
one node on the opposite side of the edge.
type Person {
office: Office
}
type Office {
person: Person @hasInverse(field: "office")
}
To define a one-to-many (1:n
) relationship, wrap the “many” side of the
relationship in a list. The following example shows that an Office
belongs to
one Company
, but a single Company can have many offices.
type Company {
offices: [Office] @hasInverse(field: "company")
}
type Office {
company: Company
}
To define a many-to-many (n:n
) relationship, wrap both sides of the relationship
in a list. The following examples shows that a Person
has many roles, and a Role
can belong to many different people.
type Person {
roles: [Role]
}
type Role {
people: [Person] @hasInverse(field: "roles")
}
One-to-one and many-to-many relationships can point to the same edge of another
node. You saw an example of this previously in our social graph schema example,
where a Person
can have multiple friends:
type Person {
friends: [Person] @hasInverse(field: "friends")
}
You can iterate on your existing schema to add or remove these bidirectional edges. If you remove one edge or side from a two-way relationship, all of the functionality and data will remain for the single-edge relationship.
Even though the GraphQL API will keep edges with @hasInverse
directives
balanced, it is possible that the edges will fall out-of-sync when you iterate
your schema or bypass the GraphQL API to access other Dgraph endpoints. A community member has posted
a script that you can run to repair unbalanced inverse relationships.
Something to try: Add a relationship from a Company
to their mascot Animal
, and
add the inverse relationship from the Animal
to the companies that it
represents.