ok, I will try and provide a full example of what I am doing.
Suppose I have several nodes, A, B, C, D that have some relationship with each other:
set {
_:A <dgraph.type> "Node" .
_:A <name> "A" .
_:B <dgraph.type> "Node" .
_:B <name> "B" .
_:C <dgraph.type> "Node" .
_:C <name> "C" .
_:D <dgraph.type> "Node" .
_:D <name> "D" .
_:B <Links> _:A .
_:C <Links> _:A .
_:C <Links> _:B .
_:D <Links> _:C .
}
Assuming each such node represents a “class” and I have some rules to create instances from that class, I would want to do that in a breadth-first fashion. This means that first I need to find all the “root” nodes. Like so:
ID as var(func:type("Node")) {
linkCount as count(Links @filter(type("Node")))
}
# find nodes no other node links to (i.e. root nodes)
rootNodes(func:uid(ID)) @filter(eq(val(linkCount), 0)) {
name
Links {
name
}
Instances {
name
}
}
Now for each of these roots, I would create an instance and attach that like so:
upsert {
query {
nodeA as var(func: type("Node")) @filter(eq(name,"A"))
}
mutation {
set {
_:X <dgraph.type> "Instance" .
_:X <name> "X" .
uid(nodeA) <Instances> _:X .
}
}
}
And now the tricky part, I want to find the next level of nodes to create instances from - but I only want to find those nodes that have relationships to nodes that already have instances.
For example, this will find both “B
” and “C
”. Because each “B
” and “C
” has a link to “A
” and then “A
” has an instance created on it.
query {
leafNodes(func:type("Node"))
@cascade
@filter(NOT has(Instances))
{
name
Links @filter(ge(count(Instances),1)) {
name
}
}
}
This is great! But “C
” also has a link to “B
”, which does not yet have an instance … and thus I cannot yet instantiate “C
” because not all of its requirements have been met.
So I would want to see “C
” in the query result only after both “A
” and “B
” have instances created, not before.