Recurse at only specified predicates


#1

Hi all.

I have a simple schema here.

<name>: string .
<parent>: uid .
<child>: uid .

Given a specific name, I want to recursively get all the children, grandchildren…, but I only need the immediate parent.

Since I cannot use recurse at the predicate like

{
  tree(func: eq(name, "bob")) {
    child @recurse 
    parent 
    name
  }
}

I tried to use a variable

{
  var(func: eq(name, "bob")) {
    parent {
      parentName as name   
    }
  }
}

{
  tree(func: eq(name, "bob")) @recurse  {
    child
    val(parentName)
    name
  }
}

but the variable is added to the parent of bob, not bob.

Thank you for your help.


(Martin Martinez Rivera) #2

Not sure how to construct it in a single query but you could try to have two different queries and combine the results in your application

{
   tree(func: eq(name, "bob")) {
    parent {
      name
    }
    name
  }
}

{
  children(func: eq(name, "bob")) @recurse  {
    child
  }
}

#3

Thank you Martin. This does work. Is there a reason why recurse at an edge is not allowed? It seems like a common use case.


(Martin Martinez Rivera) #4

Not sure since I haven’t touched that part of the codebase. I’ll take a look tomorrow to see if it’s possible to get rid of that restriction.


#5

Thank you. That would be great. Besides maybe slower, the other drawback of using two queries is that when there are multiple results, it requires merging the two query results manually by uid matching


(Martin Martinez Rivera) #6

I talked to Manish (the founder) and he said you would need two queries to do this.


(Martin Martinez Rivera) #7

Michel Conrado just pointed out to me that the following query would be more performant.

{
   tree(func: eq(name, "bob")) {
   p as uid
    parent {
      name
    }
    name
  }
}

{
  children(func: uid(p) ) @recurse  {
    child
  }
}

since the index only needs to be traversed once.


(Martin Martinez Rivera) #8

Also, if the height of your graph is constant, you could do it in a query with something like:

{
  tree(func: eq(name, "bob")) {
    child { expand(_all_) { expand(_all_) { expand(_all_) { expand(_all_) }}}}
    parent 
    name
  }
}

Again, this wouldn’t work if the number of expand(all) statements needed is not the same for every node but I am mentioning this in case it fits your use case.


#9

Got it. Using uid to query children is a great idea. Thanks.