Deleting GraphQL node with xid (String @id) does not cleanup edges to that node

Report a GraphQL Bug

What edition and version of Dgraph are you using?

Dgraph Cloud

Edition:

  • SlashGraphQL
  • Dgraph (community edition/Dgraph Cloud)

If you are using the community edition or enterprise edition of Dgraph, please list the version:

Dgraph Version
$ dgraph version
 
PASTE YOUR RESULTS HERE

Have you tried reproducing the issue with the latest release?

N/A

Steps to reproduce the issue (paste the query/schema if possible)

Expected behaviour and actual result.

For this schema:

type Block {
  id:  String! @id
  blocks: [Block!]!
}

And these mutations:

mutation {
  addBlock(input:{id:"test1", blocks:[{id:"test2", blocks:[]}]}) {
    block {
      id
      blocks {
        id
      }
    }
  }
}
mutation {
  deleteBlock(filter:{id:{eq:"test2"}}) {
    numUids
  }
}

This query will fail:

query {
  getBlock(id:"test1") {
    blocks {
      id
    }
}

With the error:

Non-nullable field 'id' (type String!) was not present in result from Dgraph.  GraphQL error propagation triggered.

A DQL query shows that while the fields of the test2 node have been deleted, the edge from test1 to the dgraph uid of the node still exists.

Just curious, what happens if you also include the ID in the schema?

type Block {
  uid: ID!
  id:  String! @id
  blocks: [Block!]!
}

Then you can query the results without requesting the Block.id that was deleted to see if the relationship still exists or not.

That works, but is more of a work around than a solution :slight_smile:

1 Like

Just trying to identify where the breakdown is. Is the relationship not being removed like it should, or is the problem with the query? I probably should run this to see it for myself instead of just keyboard warrior here trying to hash this out.

Any thoughts from team Dgraph? Seems to make external IDs somewhat unusable…

1 Like

Try it with @cascade:

J

Thank you for the suggestion. Not really looking for a work around, just raising a bug and wondering whether I should wait for a fix or work around in my codebase (which will mean removing the work around once it’s fixed :sweat_smile:)

1 Like

I don’t know that that is a workaround, but possibly the fix. Let me know if it works.

J

It does work, but it’s surely a workaround :slight_smile: I asked Dgraph to delete that node, which should include removing all edges to that node as well – it shouldn’t be a huge change to the GraphQL query generator to filter out results with no dgraph.type (which is a good indication that they’ve been deleted)

1 Like

I think you’re talking about two different things. The @cascade is not a workaround, but does solve your query problem. What you actually want, is a cascade on delete that just removes the connection(s).

This is a feature request that I made a while back. Hopefully we will see this one day, as this is how SQL handles the situation:

J

Basically what you are suggesting is that someone using the GraphQL endpoint should add @cascade to any edge query if the want to be able to delete nodes. Do I understand that correctly?

I totally understand the why of the issue, I’m just saying that any user that is not familiar with the way Dgraph (not just the GraphQL endpoint) works will think this is a bug.

Since these information-less edges serve no purpose to the GraphQL endpoint, I’m suggesting that they should be filtered out by the endpoint.

Since there are no Github issues for Dgraph any more all I can do is start a thread about it where we discuss workarounds :slight_smile:

1 Like

So @cascade is not the problem here, and is working as expected. Here is what @cascade does from the docs:

With the @cascade directive, nodes that don’t have all fields specified in the query are removed. This can be useful in cases where some filter was applied and some nodes might not have all the listed fields.

So this is correct. The real bug here is that the “informationless edges,” or “Non-nullable fields” are allowed to exist in the first place. There are only two possible fixes for this:

  1. Don’t allow them to be deleted if one edge requires it to exist (Dgraph needs to return an error in this case)
  2. Cascade delete both edges (if my @reference directive is added) - not to be confused with @cascade directive, completely different things…

The other option is what is currently happening: allowing a node with non-nullable fields to exist.

We hate this option, as it opens up a world of bad schema validation, potential query errors, etc.

@cascade is really just a filter. We don’t want unnecessary filters as our default way of querying.

J