updateMutation removes fields when they are "set" to null in remove


type Foo {
  id: String! @id
  bar: String!

Create Foo with:

  addFoo(input: [
      id: "1"
      bar: "2"
  ]) {

Update Foo using:

mutation {
  updateFoo(input: {
    filter: {
      id: {eq: "1"}
    remove: {
      bar: null
  }) {

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

Possibly related: [Bug] StringHashFilter of update mutation does not work correctly

Why is this important? Why do you send null in the first place?

Because I decide to remove that field based on a condition. I expect dgraph to not do anything if null is send on a not-required field. (This is obviously a toy example with one field where one could find workarounds. The real code has #number-of-fields optionals. Every field can either be removed, or not (set to null).

As this is the second bug of this nature that I found, I think you might want to check in general that you ignore optional fields when they are set to 0. Should be an easy fix, no?

This is intended behavior and is the way to delete a field, bar in this case without giving its value explicitly. If we don’t do this, then there is no easy way for a user to delete the value of a field without specifying the value.

I see. Sorry for the noise then.

But couldn’t we use set for this already? I.e. set: {bar: null} would essentially remove it, no?

I think this goes back to how DQL uses the Wild Card Delete.

When remove.bar is set with a value it uses:

# 0x1 would be replaced with the correct uid using upsert with XID Foo.id = 1
delete {
  <0x1> <Foo.bar> "2" .

When remove.bar is set with a nil value it uses:

delete {
  <0x1> <Foo.bar> * .

And a recent found “bug” is that this also was being applied when remove is supplied but nil (or empty object) it currently uses:

delete {
  <0x1> * * .

which deletes the entire node.

Umm, no. Imagine that the schema could be:

type Foo {
  id: String @id
  bar: [String!]!

Then your same mutation would simply not add another new null value. Also, looking at the schema from this view point, It helps understand why the need for the above bar: null to work to delete all bars or delete a specific bar by value.