Hi @myokomu, I just starting looking at dgraph yesterday and decided to model a folder/file structure to get a feel for how it might work with hierarchical data. I’m still getting my head around things but figured some of my queries might help you because they seem closely related…
Sample Data Set
A basic tree structure like:
"Folder 1"
| - "Folder 2"
| - "Folder 3"
| - "Folder 4"
| - "Folder 5"
# Add Indexes
<name>: string @index(exact, term, trigram) .
# Configure Relationships (two-way)
<parent>: uid @count .
<children>: uid @count .
# Insert Data
{
set {
<_:node1> <name> "Folder 1" .
<_:node2> <name> "Folder 2" .
<_:node3> <name> "Folder 3" .
<_:node4> <name> "Folder 4" .
<_:node5> <name> "Folder 5" .
<_:node1> <children> <_:node2> (type="unknown", date=2006-01-02T15:04:05) .
<_:node2> <parent> <_:node1> (type="unknown", date=2006-01-02T15:04:05) .
<_:node2> <children> <_:node3> (type="unknown", date=2006-01-02T15:04:05) .
<_:node3> <parent> <_:node2> (type="unknown", date=2006-01-02T15:04:05) .
<_:node1> <children> <_:node4> (type="unknown", date=2006-01-02T15:04:05) .
<_:node4> <parent> <_:node1> (type="unknown", date=2006-01-02T15:04:05) .
<_:node1> <children> <_:node5> (type="unknown", date=2006-01-02T15:04:05) .
<_:node5> <parent> <_:node1> (type="unknown", date=2006-01-02T15:04:05) .
}
}
The Queries
These were my initial attempts at bringing back the usual things you’d want from a Folder/File structure (or any hierarchy really). The key here was using @recurse
.
# Immediate Children
{
children(func: eq(name, "Folder 1")) @recurse(depth: 2) {
uid
name
children(orderasc: name) {
uid
name
}
}
}
# Immediate Parent
{
parent(func: eq(name, "Folder 3")) @recurse(depth: 2) {
uid
name
parent(orderasc: name) {
uid
name
}
}
}
# All Descendants
{
descendants(func: eq(name, "Folder 1")) @recurse {
uid
name
children(orderasc: name) {
uid
name
}
}
}
# All Ancestors
{
ancestors(func: eq(name, "Folder 3")) @recurse {
uid
name
parent(orderasc: name) {
uid
name
}
}
}
One challenge I ran into was trying to find all siblings without making a mess of the data response and creating repetition/bloat. The @normalize
enabled me to get what I wanted and actually helped me rewrite the two of the above.
# Siblings
{
siblings(func: eq(name, "Folder 2")) @normalize {
uid
name
parent {
uid
name
children(orderasc: name) {
uid: uid
name: name
}
}
}
}
# Immediate Children
{
children(func: eq(name, "Folder 1")) @normalize {
uid
name
children(orderasc: name) {
uid: uid
name: name
}
}
}
# Immediate Parent
{
parent(func: eq(name, "Folder 3")) @normalize {
uid
name
parent(orderasc: name) {
uid: uid
name: name
}
}
}
Taking it a step further I was able to put together an array forming the path’s crumbs
which I felt could be useful…
# Path Crumbs (from parent)
{
paths(func: eq(name, "Folder 1")) @normalize @recurse {
uids: uid
crumbs: name
children(orderasc: name) {
uid
name
}
}
}
Thoughts
No idea how performant these types of queries are vs. the ones previously mentioned. Also I’m not sure that the @normalize
option is conventional to use because you are effectively returning an array instead of a clear relationship with a central/start node, BUT in the case of siblings it was nice because it seemed like otherwise I would have to return the node its parent and then all its children which seemed unnecessary. Anyways, I figured I’d share these incase they help.
–
Jon