I would modify your example schema above with inverse edges if using GraphQL like the following
interface Record {
id: ID!
updatedAt: DateTime!
}
type User implements Record {
name: String!
typeAInverse: [TypeA] @hasInverse(field: "users")
# ...
}
type TypeA implements Record {
users: [User]
typeBInverse: [TypeB] @hasInverse(field: "typeA")
# ...
}
type TypeB implements Record {
typeA: TypeA
typeCInverse: [TypeC] @hasInverse(field: "typeC")
# ...
}
type TypeC implements Record {
typeB: TypeB
# ...
}
NOTE: If you use DQL and not GraphQL you could just add the @reverse
directive. And also note that in Dgraph, when creating a schema with types implementing interfaces you do not have to define the repeated fields in every type. They auto inherit all fields from the interface.
Then you could traverse the graph from the user.
query {
getUser(id:"0x2") {
...RecordFields
typeAInverse {
...RecordFields
typeBInverse {
...RecordFields
typeCInverse {
...RecordFields
}
}
}
}
fragment RecordFields on Record {
id
updatedAt
# ...
}
}
If you need it to be a flat list then you could use DQL and the normalize directive.
If you wanted to group all of these branches together into one trunk to paginate, you would do that with DQL (I will use the DQL schema that would be generated by my GraphQL schema above. This could be simplified to only DQL with reverse directive on edges):
query {
user as var(func: uid("0x2")) {
typeA as User.typeAInverse {
typeB as TypeA.typeBInverse {
typeC as TypeB.typeCInverse
}
}
}
records(func: uid(user,typeA,typeB,typeC), orderdesc: Record.updatedAt, first: 5, offset: 5) {
uid
Record.updatedAt
# ...
# Could also query things here like `User.name` or `TypeA.users`, etc.
}
}
For completeness here would be a simple DQL schema:
updatedAt: datetime
name: string
users: [uid] @reverse
typeA: [uid] @reverse
typeB: [uid] @reverse
type Record {
updatedAt
}
type User {
name
updatedAt
}
type TypeA {
users
updatedAt
}
type TypeB {
typeA
updatedAt
}
type TypeC {
typeB
updatedAt
}
and simplified DQL query equal to above using reverse ~
query {
user as var(func: uid("0x2")) {
typeA as ~users {
typeB as ~typeA {
typeC as ~typeC
}
}
}
records(func: uid(user,typeA,typeB,typeC), orderdesc: updatedAt, first: 5, offset: 5) {
uid
updatedAt
# ...
# Could also query things here like `name` or `users`, etc.
}
}