I am looking for a graphdb which can actually support inheritance in nodes. (e.g. Author subclassOf Person subclassOf PhysicalIndividual and so on).
I learnt that such things are possible through graphql interfaces. But can this inheritance be implemented in Dgraph?
This is required for numerous use cases which I want to support via my graph database.
I am currently a neo4j user and inheritance is not its default feature. I don’t want to introduce “IS_A” relation, neither do I want to switch to RDF-store either.
So, I am searching for a graph db with such capability. Please suggest.
The short answer to your question is, Dgraph does support GraphQL type inheritance natively in its GraphQL API endpoint.
To get more technical about how it does this, and some of the caveats of it keep reading…
Dgraph’s GraphQL API is a subset of functions in the core of Dgraph rewriting requests into DQL (Dgraph Query Language). DQL was developed to be similar to GraphQL syntax but deviated with functionality so it could be used as an actual Database Query Language. More about this from these official doc pages:
To explain this a little more in detail let’s use an example:
interface PhysicalIndividual {
id: ID!
dateOfBirth: DateTime!
}
interface Person implements PhysicalIndividual {
name: String! @search
}
interface Author implements Person {
authored: [Book] @hasInverse(field: "authors")
}
type Book {
id: ID!
name: String! @search
authors: [Author] @hasInverse(field: "authored")
}
so this ^ is GraphQL interface inheritance which you were referring to, and if you pass this GraphQL schema into Dgraph then it will generate the API and DQL schema to support this inheritance as you would expect it to work.
Now how this looks in the DQL schema and type system is a little more complicated or simple depending on how you look at it. Dgraph’s DQL type system does not support what GraphQL terms an interface but it does support nodes with multiple types. So this in DQL schema would look something like:
type PhysicalIndividual {
PhysicalIndividual.dateOfBirth
}
type Person {
Person.name
}
type Author {
Author.authored
}
type Book {
Book.name
Book.authors
}
PhysicalIndividual.dateOfBirth: datetime .
Person.name: string @index(term) .
Author.authored: [uid] .
Book.name: string @index(term) .
Book.authors: [uid] .
Now a node that is a Author could look something like:
One of the problems with this, is that in DQL, there is no garentee that a node inherits the classes correctly. For example, you could have a node that has the types: ["Book","Person"] which doesn’t logically make sense, but the type system in DQL would allow it.
If you can only stay in Dgraph’s GraphQL API then you might be safe. Be sure to give a good look over:
However if you when you need to use DQL, you will need to write a logical layer in your own custom API to make sure that types are inherited correctly, and that required fields are actually required. (DQL type system has no concept of required fields).
The examples above hinted at some of the manually conversions you will need to consider with GraphQL <> DQL interoperability with field renaming, etc. I also prefer using DQL’s @reverse directive with reverse fields by ~field over Dgraph’s GraphQL @hasInverse directive which creates bi directional edges and can get nasty quick if you don’t also manually manage these inverse edges with any DQL mutations you use.
Thanks you Anthony for such a detailed explanation. It clears many doubts. Let me go through this in detail and see if I can avoid or minimize manually writing the logic layer.
This is super interesting! Does it mean that DQL is less expressive than OWL/RDF? This implies a large gap between the two model, right? If DQL can’t manage hierarchies of classes, there are a lot of situations that can’t be modeled/expressed.
But, if I understand well, this caveat doesn’t exists in GraphQL (which Dgraph can interpret properly nevertheless) because it allows for towers of “implement”.