Id not allowed multiple times in same sub-query

Hi,

I’m running into this error message, which I suspect is a bug, but I wanted to check first before filing an issue.

When I run the following query, Dgraph responds with an error:

query {
  organizationScalar(func: has(externalId)) @filter(eq(externalId, "tyrell")) {
    ...Fragment
    id: uid
  }
}

fragment Fragment {
  id: uid
  title
}

This is the error:

{
  "errors": [
    {
      "code": "ErrorInvalidRequest",
      "message": ": id not allowed multiple times in same sub-query."
    }
  ],
  "data": null
}

The error goes away if I delete one or the other of the “id: uid” fields.

I suspect this is a bug, but I’m not sure if this is the case. The reason I think this is an error is that in a framework like React/Relay, the fragments are used to hide fields from components that do not request them. So the component requesting the initial query will see a different set of fields than the component requesting the embedded fragment, and they should both be able to request the id field and not coordinate between themselves to share this information. It is the job of the GraphQL server to consolidate redundant fields when the query is received.

Does a similar principle apply to GraphQL±? Is this a bug or is it intended behavior?

In your case, you’re technically doing something similar to that.

query {
  organizationScalar(func: has(externalId)) @filter(eq(externalId, "tyrell")) {
      id: uid
      title
      id: uid
  }
}

Maybe you wanted to do something like this:

query {
  organizationScalar(func: has(externalId)) @filter(eq(externalId, "tyrell")) {
    ...Fragment
    id: uid
  }
}

fragment Fragment {
 someOrganization {
          id: uid
          title
    }
}

This is allowed in GraphQL (although perhaps not GraphQL±). The reason I assume it’s allowed in GraphQL is that (e.g., in Relay) each fragment is colocated with with a React component, and components are written as standalone things that do not need to take into account implementation details of other components. If two components need the same field, they’ll create fragments in the same parent that request the same field (redundantly).

In Dgraph, we expand out the fragment internally. And just as a general rule, we don’t allow requesting the same predicate on the same level multiple times for performance reasons. Seems like this should be easy to work around.

The performance justification seems good, but it doesn’t apply in the case of GraphQL servers, which in my experience deduplicate the redundant fields on the server and merge the field subtrees in the response; it is then left to the client cache (Relay) to multiplex the merged fields in the response from the server back to the fragments with their redundant field specifications. So this capability in GraphQL is partly just syntactic sugar. (There is one real difference: when you request the same field more than once, each time with different arguments.)

(Relying vague memory on this; my recollection could be very wrong.)

I think I can work around Dgraph’s constraint, but I foresee possible corner cases in which the same fragment is embedded in multiple subqueries which will require some thought to aoid triggering this Dgraph error response.

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