Dgraph: Duplicate nodes with @upsert set in the schema

Created on 27 Apr 2018  路  3Comments  路  Source: dgraph-io/dgraph

Hi,

We have the following predicate set the our schema:

user: string @index(exact) @upsert .

Define a user struct

type User struct {
    UID  string `json:"uid,omitempty"`
    User string `json:"user,omitempty"`
}

Create a user (TestUserA for example) and apply mutation:

        u := &User{
        User: "TestUserA",
    }

        // Apply dgraph mutation
    mu := &api.Mutation{}
    mu.CommitNow = true
    pJson, err := json.Marshal(u)
    if err != nil {
        return nil, err
    }
    mu.SetJson = pJson
    assignedData, err := txn.Mutate(ctx, mu)
    if err != nil {
        return nil, err
    }

    assigned, err := json.Marshal(&assignedData)
    if err != nil {
        return nil, err
    }

Run the create user query 3 times and we get 3 user nodes:

{
  "data": {
    "domain": [
      {
        "uid": "0x11",
        "user": "TestUserA"
      },
      {
        "uid": "0x12",
        "user": "TestUserA"
      },
      {
        "uid": "0x13",
        "user": "TestUserA"
      }
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 10000,
      "processing_ns": 152000,
      "encoding_ns": 581000
    },
    "txn": {
      "start_ts": 29,
      "lin_read": {
        "ids": {
          "1": 35
        }
      }
    }
  }
}

Are we doing something wrong?
Shouldn't node 0x11 get updated if @upsert is specified in the schema?

kinquestion

Most helpful comment

Adding the @upsert directive doesn't mean that the database would check for the value first. The user should do the query first to check and if the value is not found then it should try and add the value.

What the @upsert directive ensures is that it if you were adding the same value concurrently with different transactions, then only one of them would succeed and others would abort. You can read some docs about the upsert procedure and see the example at https://github.com/dgraph-io/dgraph/blob/4d6a6077343570518cbe247fa1fbf9320731b09b/contrib/integration/acctupsert/main.go#L130.

All 3 comments

Wow! I guess, you are not alone, I did same exact thing in "query browser" and I too got the replicated data.

Just in case, anyone wants to replicate, I have done below things :-

In alter tab of query browser (dgraph-ratel), I ran below code:-

user: string @index(exact) @upsert .

in Mutation tab of Query browser (dgraph-ratel), I ran below mutation 3 times:-

{
    set {
        _:userA <user> "testUser"
   }
}

and all three time, I got the response "Done"

Now, in Query tab section of Query browser (dgraph-ratel):-

{
  all(func: eq(user, "testUser")) {
    uid
    user
  }
}

I got the response as below :-

{
  "data": {
    "all": [
      {
        "uid": "0x1",
        "user": "testUser"
      },
      {
        "uid": "0x2",
        "user": "testUser"
      },
      {
        "uid": "0x3",
        "user": "testUser"
      }
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 31000,
      "processing_ns": 292000,
      "encoding_ns": 1081000
    },
    "txn": {
      "start_ts": 10046,
      "lin_read": {
        "ids": {
          "1": 16
        }
      }
    }
  }
}

Adding the @upsert directive doesn't mean that the database would check for the value first. The user should do the query first to check and if the value is not found then it should try and add the value.

What the @upsert directive ensures is that it if you were adding the same value concurrently with different transactions, then only one of them would succeed and others would abort. You can read some docs about the upsert procedure and see the example at https://github.com/dgraph-io/dgraph/blob/4d6a6077343570518cbe247fa1fbf9320731b09b/contrib/integration/acctupsert/main.go#L130.

@pawanrawal ok that makes sense, "Concurrently" is the main reflective difference that makes using "upsert" and non "upsert".

Thanks :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

allen-munsch picture allen-munsch  路  4Comments

andrewsmedina picture andrewsmedina  路  4Comments

jimanvlad picture jimanvlad  路  5Comments

fritzblue picture fritzblue  路  5Comments

KadoBOT picture KadoBOT  路  5Comments