Recursion design question

I have a design problem concerning recursion. I want to create a simple reddit-like comments tree.
A comments has the following structure:

  • content: string
  • author: uid
  • comments: uid # The list of the others comments

I can retrieve ONE comment with the following request (which works):

{
  get_one_comment(func: uid("0x139")) {
    author {
      uid
    }
    content
  }
}

But when I try to retrieve all the comments recursively with the following requests: (doesn’t work)

{
  get_all_comments(func: uid("0x139")) @recurse(depth: 0) {
    author {
      uid
    }
    content
    comments #recursive call
  }
}

I have the following error:

recurse queries require that all predicates are specified in one level

It seems that following an edge in a recursive query is forbiden.
Is there a way to retrieve recusively both the comment_content and the comment_author ?

Thanks for reading.

It says “one level”, you have to define the edges/preds in one level to be used by the recurse query in all levels it finds.

{
  get_all_comments(func: uid("0x139")) @recurse(depth: 1) {
    uid
    author
    content
    comments #recursive call
  }
}

Thanks for answering.

And if would like to display both the comment content and the author name, I need to collect all the author ids from this request answer and then in an other request retrieve all the author names. Is that right or is there an easiest way to do ?

I didn’t get what you said. In a recursive query, you have to add all attributes and relations you know that exists and you need.

I don’t quite understand your last question if it is related to Recurse or is it another matter.

Questions:
Display where? or how?
Display unrelated entities in a list?
What is the structure of your data? (Only queries don’t help)
“get_all_comments” are the “request answer”?

It’s plausible, but I need to understand its structure and context to be able to help.

Sorry I was not clear, I’ll will give a little more context.
I have 2 nodes Comment and Author:

Node Comment:
- uid
- content: string # The comment message
- authored: uid # Predicate to the node author
- comments: uid # Predicate the the other comments (for recursion)

Node Author:
- uid
- author_name string 

My goal is to display on the front-end (web app) all the comments with for each comment the associated author_name.
With the recursive query on comments, I cannot retrieve the author_name because it breaks the “one level predicate recurse limitation”.
Thus it seems the only way I found to retrieve the author_name is by adding the following steps:

  1. First I update the schema and I add the “author_id” directly as string because this one can be retrieved on the recursive query.
Node Comment:
- uid
- content: string # The comment message
- author_id: string # ADDED to be retrieved on the recursive call
- authored: uid # Predicate to the node author
- comments: uid # Predicate the the other comments (for recursion)

Node Author:
- uid
- author_name string 
  1. I execute the recursive query. In the response I retrieve programmatically all the author_id and I create a second query that given my list of “author_id” retrieves the “author_name” which is the one I wan to display on the front-end side.

Thus, I find this solution quite cumbersome. That’s why I’m asking if I’m doing something wrong and if there is an easiest alternative ?

That’s not a limitation. It’s a rule. You can retrieve anything from a recursive query.

Okay, I’ll work on a sample based on what you wrote and come up with something.

Okay, I did a sample so we can work this out.

I did three kinds of entities. As you mentioned Reddit. It is fair enough to add “Thread”.

type Author {
    author_name
 }

type Comment {
    content
    author
    authored # I'm not sure what authored means in that context
    comments
 }

type Thread {
    author
    comments
    content
 }

    author_name: string .
    content: string .
    author: uid .
    comments: [uid] .

The Dataset (Sample)

{
   "set": [
      {
         "author": {
            "uid": "_:Maria"
         },
         "content": "Sed non tempor nisi, lobortis rhoncus mi. In cursus nibh a tellus congue, non blandit nunc rhoncus. Suspendisse sit amet mi ac dui convallis commodo sed feugiat velit. Nam luctus vel velit eget commodo. Etiam laoreet vestibulum elementum. Maecenas sodales magna turpis, vitae rhoncus sapien bibendum ac. Nunc lobortis lectus arcu, nec tristique metus aliquam vel.",
         "comments": [
            {
               "content": "Cras varius ac eros sit amet posuere. Etiam eget ultricies elit. Morbi iaculis nisl et risus elementum tincidunt. Nunc ornare metus a velit pretium ultrices. Cras consequat, libero eu suscipit scelerisque, metus eros semper ligula, vitae sagittis purus libero sit amet erat. ",
               "author": {
                  "uid": "_:Lucas"
               },
               "authored": "x",
               "comments": {
                  "content": "Sed non tempor nisi, lobortis rhoncus mi. In cursus nibh a tellus congue https://www.lipsum.com/feed/html",
                  "author": {
                     "uid": "_:anonymous"
                  },
                  "authored": "x",
                  "dgraph.type": "Comment"
               },
               "dgraph.type": "Comment"
            },
            {
               "content": "Ut turpis nulla, ultrices at arcu vel, egestas aliquet ante. Nulla velit nisl, iaculis ac aliquam facilisis, molestie sit amet tellus. Morbi ornare ultrices accumsan. Pellentesque vel eros eu lacus eleifend vestibulum.",
               "author": {
                  "uid": "_:anonymous"
               },
               "authored": "x",
               "dgraph.type": "Comment"
            }
         ],
         "dgraph.type": "Thread"
      },
      {
         "author": {
            "uid": "_:Maria"
         },
         "content": "Morbi eget ante dictum, consequat purus non, ullamcorper diam. Aenean dapibus odio elit, eget vulputate nulla aliquam ac. Etiam egestas sit amet ipsum pharetra pharetra. ",
         "comments": [
            {
               "content": "Vestibulum sit amet eleifend erat",
               "author": {
                  "uid": "_:Julius"
               },
               "authored": "x",
               "comments": {
                  "content": "Morbi tempor velit erat, quis egestas ipsum maximus facilisis.",
                  "author": {
                     "uid": "_:anonymous"
                  },
                  "authored": "x",
                  "dgraph.type": "Comment"
               },
               "dgraph.type": "Comment"
            },
            {
               "content": "Nullam quis sollicitudin ligula. Fusce id commodo libero.",
               "author": {
                  "uid": "_:Lucas"
               },
               "authored": "x",
               "comments": {
                  "content": "Morbi tempor velit erat, quis egestas ipsum maximus facilisis.",
                  "author": {
                     "uid": "_:anonymous"
                  },
                  "authored": "x",
                  "dgraph.type": "Comment"
               },
               "dgraph.type": "Comment"
            }
         ]
      },
      {
         "uid": "_:Maria",
         "author_name": "Maria",
         "dgraph.type": "Author"
      },
      {
         "uid": "_:Julius",
         "author_name": "Julius",
         "dgraph.type": "Author"
      },
      {
         "uid": "_:Lucas",
         "author_name": "Lucas",
         "dgraph.type": "Author"
      },
      {
         "uid": "_:anonymous",
         "author_name": "anonymous",
         "dgraph.type": "Author"
      }
   ]
}

Querying

This query is just an example, as I have only one Thread I did not use functions. Just the Type.

{
  get_one_Thread(func: type(Thread)) @recurse {
    author 
    uid
    author_name
    content
    comments
  }
}

Result

As you can see in the result, using recurse I was able to expand Thread and its comments normally.

{
  "data": {
    "get_one_Thread": [
      {
        "author": {
          "uid": "0xc0e28",
          "author_name": "Maria"
        },
        "uid": "0xc0e27",
        "content": "Sed non tempor nisi, lobortis rhoncus mi. In cursus nibh a tellus congue, non blandit nunc rhoncus. Suspendisse sit amet mi ac dui convallis commodo sed feugiat velit. Nam luctus vel velit eget commodo. Etiam laoreet vestibulum elementum. Maecenas sodales magna turpis, vitae rhoncus sapien bibendum ac. Nunc lobortis lectus arcu, nec tristique metus aliquam vel.",
        "comments": [
          {
            "author": {
              "uid": "0xc0e2e",
              "author_name": "Lucas"
            },
            "uid": "0xc0e2d",
            "content": "Cras varius ac eros sit amet posuere. Etiam eget ultricies elit. Morbi iaculis nisl et risus elementum tincidunt. Nunc ornare metus a velit pretium ultrices. Cras consequat, libero eu suscipit scelerisque, metus eros semper ligula, vitae sagittis purus libero sit amet erat. ",
            "comments": [
              {
                "author": {
                  "uid": "0xc0e26",
                  "author_name": "anonymous"
                },
                "uid": "0xc0e2f",
                "content": "Sed non tempor nisi, lobortis rhoncus mi. In cursus nibh a tellus congue https://www.lipsum.com/feed/html"
              }
            ]
          },
          {
            "author": {
              "uid": "0xc0e26",
              "author_name": "anonymous"
            },
            "uid": "0xc0e30",
            "content": "Ut turpis nulla, ultrices at arcu vel, egestas aliquet ante. Nulla velit nisl, iaculis ac aliquam facilisis, molestie sit amet tellus. Morbi ornare ultrices accumsan. Pellentesque vel eros eu lacus eleifend vestibulum."
          }
        ]
      }
    ]
  }
}

If you can suggest changes to my Sample to fit your context. Please do it. The more aligned we are, the better.

1 Like

Thanks a lot @MichelDiz for your very clear example.

My misunderstanding came from the fact I didn’t know I can recurse on both “comments” and “author” at the same time.

Problem resolved :smiley:

1 Like