Why only allow one level of predicates after root in a recurse block?

According to https://docs.dgraph.io/query-language/#recurse-query, you can specify only one level of predicates after root. And indeed, this query doesn’t return any results:

{
    recursive(func: eq(name, "a")) @recurse {
        child {
          name
        }
    }
}

Firstly, this should actually error out, and it’s quite confusing that it doesn’t.

Secondly, I think it would be nice if we could just recurse on the top level predicates (as before), while still expanding the lower level predicates at each iteration. Of course, you can work around it by assigning the children to a variable and finding their names in another block, but I think it would be nicer if the above query gave us the full tree of children with their names.

If anyone wants to try, I tested this on 197e1d5e4cb642c81d833fb510c7758a1fff9ff6, with this data:

{
    set {
    _:a <name> "a" .
    _:a <child> _:b .

    _:b <name> "b" .
    _:b <child> _:c .

    _:c <name> "c" .
    _:c <child> _:d .

    _:d <name> "d" .
    _:d <child> _:e .

    _:e <name> "e" .
    _:e <child> _:f .

    _:f <name> "f" .
    _:f <child> _:g .
    }
}

and this schema:

name: string @index(exact) .
%s: uid @reverse .

Hey @BlakeMScurr

Agree, this should error out. I will make a fix so that it does.

Now, I think there is some confusion about either how recurse works or I am not able to understand what you are trying to achieve here.

In recurse, you specify a set of predicates and we try to expand along those predicates at every level until we cant expand further. So they are not top-level predicates.

This query should give you names of all children.

{
    recursive(func: eq(name, "a")) @recurse {
        child
        name
    }
}

Hey @pawan :smiley:

Thanks, that solves the problem I presented and puts me on the right track. However, I realized I have oversimplified and miscommunicated my problem. (By the way, this might be an unimportant edge case, and I do have a workaround).

The real issue has to do with variables and recursion depth.

Suppose I take your query, give it a finite depth, and assign the children to a variable:

{
    recursive(func: eq(name, "a")) @recurse(depth: 4) {
        children as child
        name
    }

    showChildren(func: uid(children)) {
        name
  }
}

I expected the names from the two blocks to be the same, but in fact the first gives {a,b,c,d}, while the second gives {b,c,d,e} which makes sense. I was hoping to make the two have the same value {b,c,d,e} by using name underneath child (and not expanding the name predicate) like I mentioned before:

{
    recursive(func: eq(name, "a")) @recurse(depth: 4) {
        children as child {
            name
        }
    }

    showChildren(func: uid(children)) {
        name
  }
}

The reason this matters is that my application checks the uids (I’ll stick with name here, but I think the principle is the same) returned from each block to check if a result from one block is the child of a result from another. So if we try to get the children at depth 2 from nodes a and d:

{
    recursive(func: anyofterms(name, "a d")) @recurse(depth: 2) {
        children as child 
        name
    }

    showChildren(func: uid(children)) {
        name
  }
}

we get:

"recursive": [
      {
        "child": [
          {
            "name": "b"
          }
        ],
        "name": "a"
      },
      {
        "child": [
          {
            "name": "e"
          }
        ],
        "name": "d"
      }
    ],
"showChildren": [
    {"name": "b"},
    {"name": "c"},
    {"name": "e"},
    {"name": "f"}
]

and the question is; which results from recursive correspond to which results from showChildren? We don’t have enough information know where node f comes from because of the inconsistency outlined earlier.

I have a workaround where I just set depth to originalDepth+1 and invalidate the extra results. And as I said before, I don’t know if this is a problem for DGraph itself, or if it’s just an edgecase.

Ok, I now understand the behaviour that you are expecting. I can confirm that recurse is working as expected. I will try to explain how to make it more clear.

{
    recursive(func: eq(name, "a")) @recurse(depth: 4) {
        children as child
        name
    }
}

The above query tries to expand upto 4 levels.

name="a"       Level 0
|
child, name    Level 1   (Here child would be b and name a corresponding to node at level 0)
|
child, name    Level 2   (Child being c and name b)
|
child, name    Level 3   (Child d and name c)
|
child, name    Level 4   (Child e and name d)

Name e would come at Level 5 here and the variable children stores the child nodes as b, c, d and e. You could use depth + 1 as you said.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.