Recurse in custom resolver

I’m trying to implement a GraphQL custom resolver using DQL to recurse nodes (as I believe so far is the only way to have recurse feature in GraphQL).
However it is just returning only the first child node. If I run same code in DQL it works correctly. I tried to follow custom resolver guidelines in the docs, but no success. I’ve also tried to find similar question or references for this but couldn’t find any.

Info:
Dgraph v21.12.0, Deployed in kubernetes with dgraph/dgraph docker image.

Schema added to /admin/schema :

type TestDto @generate(
  query: {
    get: true,
    query: true,
    password: false,
    aggregate: true
  },
  mutation: {
    add: false,
    update: false,
    delete: false
  },
  subscription: false
) {
  mrId: String! @search(by: [hash])
  targetObjects: [TestDto] 
}

type Query {

  queryTestDtoSubtree(mrId: String!): [TestDto] @custom(dql: """
    query q($mrId: string!) {

      var(func: eq(TestDto.mrId, $mrId)) @recurse(depth: 300, loop: false) {
        descendants as TestDto.targetObjects
      }

      queryTestDtoSubtree(func: uid(descendants)) {
        mrId: TestDto.mrId
      }

    }
  """)

}

Mutation (will create tree as as mrId: mynodeid1 → mrId: mynodeid2 → mrId: mynodeid3)

{
  set {
    _:x <TestDto.mrId> "mynodeid1" .
    _:x <dgraph.type> "TestDto" .
    _:y <TestDto.mrId> "mynodeid2" .
    _:y <dgraph.type> "TestDto" .
    _:z <TestDto.mrId> "mynodeid3" .  
    _:z <dgraph.type> "TestDto" .
  
    _:x <TestDto.targetObjects> _:y .
    _:y <TestDto.targetObjects> _:z .
  }
}

GraphQL query using custom resolver:

{
  queryTestDtoSubtree(mrId: "mynodeid1") {
    mrId
  }
}

Returns only first child node:

  "queryTestDtoSubtree": [
    {
      "mrId": "mynodeid2"
    }
  ]

But if run similar query with DQL:

      var(func: eq(TestDto.mrId, "mynodeid1")) @recurse(depth: 300, loop: false) {
        descendants as TestDto.targetObjects
      }

      queryTestDtoSubtree(func: uid(descendants)) {
        mrId: TestDto.mrId
      }

returns recursive results correctly:

{
  "queryTestDtoSubtree": [
    {
      "mrId": "mynodeid2"
    },
    {
      "mrId": "mynodeid3"
    }
  ]
}

Maybe there is limitations with recurse in GraphQL?
Or maybe I’m missing some directive or formatting?

Thanks!!
Cristiano.

Recurse is not possible as far as I know with GraphQL cuz it is a hard typed language. You would need to build the schema on the fly based on the recurse results. And that would be a very hacky way of doing it.

Hey @cpcostaneves,

Using 21.03.02 and loading the data thusly (live loader with a static json file):

[
    {
        "dgraph.type": "TestDto",
        "TestDto.mrId": "mynodeid1",
        "uid": "_:x",
        "TestDto.targetObjects": [
            {
                "uid": "_:y"
            }
        ]
    },
    {
        "dgraph.type": "TestDto",
        "TestDto.mrId": "mynodeid2",
        "uid": "_:y",
        "TestDto.targetObjects": [
            {
                "uid": "_:z"
            }
        ]
    },
    {
        "dgraph.type": "TestDto",
        "TestDto.mrId": "mynodeid3",
        "uid": "_:z"
    }    
]

seems to work for me. The graphql query returns:

{
  "data": {
    "queryTestDtoSubtree": [
      {
        "mrId": "mynodeid2"
      },
      {
        "mrId": "mynodeid3"
      }
    ]
  },
  "extensions": {
<snip>
}

If you wanted to capture the lineage of the target objects, you could use a technique that I’ve used in a knowledge graph that I maintain:

  queryTestDto {
    mrId
    targetObjects {
      mrId
      targetObjects {
        mrId
        targetObjects {
          mrId
          targetObjects {
            mrId            
          }
        }
      }
    }
  }

Obviously that becomes a bit unwieldy for very deep edges, but not so bad if the maximum depth is manageable. And graphQL fragments can help with the verbosity if the node has many edges.

Hi @matthewmcneely,

I’ve tried to import exactly same json data you posted using /mutate endpoint but still getting just the first node.

Query:

queryTestDtoSubtree(mrId: "mynodeid1") {
    mrId
}

Returns:

"queryTestDtoSubtree": [
    {
         "mrId": "mynodeid2"
    }
]

I also tried the whole thing from scratch and using your json data format, but no success.
If I use your last query (queryTestDto adding nested objects), then it returns all lineage.

Really strange. Have you used anything different in your graphql query, or just the same thing I did above?

Thanks for the help on this.
Having a way to recurse from graphql (for any depth, without having to specify nested objects in query) is critical for us.

Hmm, maybe there’s some difference using the /mutate endpoint vs the live loader.

Can you try the steps on this branch: https://github.com/matthewmcneely/dgraph-v23.01-sandbox/tree/explanations/graphql-recursive-query ?

Note that this is based on 23.03.2. Is that the version you’re trying with?

^ nope

@amaster507 (thanks for your help)

@cpcostaneves I can confirm that this is failing for me under 21.12.0. Do you have the option to move back to 21.03.02?

@matthewmcneely I’ve tried to downgrade back to 21.03.02 (just changed docker image tag in a test cluster) but got this:

2022/08/11 18:53:03 manifest has unsupported version: 65544 (we support 8).
Please see https://github.com/dgraph-io/badger/blob/master/README.md#i-see-manifest-has-unsupported-version-x-we-support-y-error on how to fix this.
Error while creating badger KV posting store

I was expecting this kind of data manifest issues :slight_smile: .

The docs tell me I need to dump and load using badger (and for upgrades, I don’t know if this will work for downgrades).
Ref: https://github.com/dgraph-io/badger/blob/master/docs/content/faq/index.md#i-see-manifest-has-unsupported-version-x-we-support-y-error

To downgrade I will plan it better since I have some test cluster with data I want to keep.

I wonder if dgraph development will be active from now on to see this solved in the near future :).

Thanks for helping investigating this!!

No problem. As for downgrading, I would probably choose to RDF export/import…