Recursively counting all children

What I want to do

I want to count all children of a node recursively until every node has been traversed. You can think of it as a nested comment situation. Where you have, for instance, a forum post with comments and in turn an infinite amount of replies to each comment. And each reply can also have several replies and so forth. The task would be to calculate the total number of all replies for each top-level comment. In this scenario, the relationship is a tree-like structure.

I have been trying this for a while now, but could not come up with a query that solves this. I also didn’t find a similar question or a matching example in the docs.

What I did

Schema:

_:a <name> "Alpha" .

_:a <owns> _:b .
_:b <owns> _:c .
_:c <owns> _:d .
_:c <owns> _:e .
_:c <owns> _:f .
_:f <owns> _:g .

I want to know how many Nodes are totally owned by Alpha (answer is 6)

If I run this query

{
  q(func: eq(name, "Alpha")) @recurse {
    count(owns)
}
}

I get the result 1. So if I try to aggregate them, I get an error:

{
  q(func: eq(name, "Alpha")) @recurse {
    c as count(owns)
}
  res() {
    sum(val(c))
}

I only know how to do it the complicated way:

{
	q(func: eq(name, "Alpha"))  {
    name
    c as count(owns)
    owns { d as count(owns)
    				owns { e as count(owns) }
         }
    res: math(c + d + e)
    }
}
1 Like

Try this

{
  me as var(func: eq(name, "Alpha")) 

  var(func: uid(me)) @recurse {
    A as uid
    owns
  }

  res(func: uid(A)) @filter(not uid(me)) {
    count(uid)
  }
}

3 Likes

Thanks for the quick help! This query works very well on a single node.

How would I run the same query on a more abstract level? Because if I want to know the count for all nodes of the same type, this query doesn’t work anymore.

{
  me as var(func: type(Comment)) @recurse {
    A as uid
    owns
  }
  res(func: uid(A)) @filter(not uid(me)) {
    count(uid)
  }
}

result = 0

Try to remove the “me” variable for a sec. Also, I think, based in your comment, that you gonna need to groupby.

1 Like

https://dgraph.io/docs/query-language/recurse-query/#

I dont understand @recurse that well, is this definition of @recursive right?

“Sometimes we want to loop through edges and query or count some things, but we don’t know the level of how far the edges is nested (best examples: reddit comments, where you can reply to replies infinitely), so instead of having a PITA and writing big 9999999layers deep nested query to get all our reddit replies, we just use @recursive

Is my explanation correct?

Yep, seems reasonable to me.

1 Like