1-to-1 relation overwrite in transaction doesn't work anymore

Moved from GitHub dgraph/5017

Posted by emile-tawfik:

The issue

In v1.1.x with introduction of single relations, the only way to overwrite a single relation was to use multiple mutation in single transaction (delete + insert) (https://github.com/dgraph-io/dgraph/issues/4136).
However, it seems this method doesn’t work anymore since v1.2.2 because of a bug.

What version of Dgraph are you using?

The issue exists on v1.2.2 and master.
The issue doesn’t exist on v1.2.1

Steps to reproduce the issue (command/config used to run Dgraph).

There is a test I wrote to reproduce the issue. I added it in query/query4_test.go.

func TestOverwriteOneToOneRelationInATransaction(t *testing.T) {
	schema := `
		onetoonerel: uid .
		data: int .

	triples := `
		_:node1 <onetoonerel> _:node2 .
		_:node2 <data> "42" .
	resp, err := client.NewTxn().Mutate(context.Background(), &api.Mutation{
		SetNquads: []byte(triples),
		CommitNow: true,
	require.NoError(t, err)

	node1Uid := resp.Uids["node1"]
	node2Uid := resp.Uids["node2"]

	txn := client.NewTxn()

	_, err = txn.Mutate(context.Background(), &api.Mutation{
		DelNquads: []byte(fmt.Sprintf("<%s> <onetoonerel> <%s> .", node1Uid, node2Uid)),
	require.NoError(t, err)

	resp, err = txn.Mutate(context.Background(), &api.Mutation{
		SetNquads: []byte(fmt.Sprintf(`<%s> <onetoonerel> _:node3 .
		_:node3 <data> "24" .`, node1Uid)),
	require.NoError(t, err)

	node3Uid := resp.Uids["node3"]
	err = txn.Commit(context.Background())
	require.NoError(t, err)

	query := fmt.Sprintf(`{
		me(func:uid(%s)) {
			onetoonerel {
	}`, node1Uid)
	js := processQueryNoErr(t, query)
	require.JSONEq(t, fmt.Sprintf(`
		"data": {
			"me": [
					"uid": "%s",
					"onetoonerel": {
						"uid": "%s"
	`, node1Uid, node3Uid), js)

Expected behaviour and actual result.

After a bisect it seems that the bug was introduced in https://github.com/dgraph-io/dgraph/commit/cc495fc1dca642b81db955de0ae6855da34a052c

Expected the test to pass.

--- FAIL: TestOverwriteOneToOneRelationInATransaction (1.07s)
                Error Trace:    query4_test.go:1596
                Error:          Not equal: 
                                expected: map[string]interface {}{"data":map[string]interface {}{"me":[]interface {}{map[string]interface {}{"onetoonerel":map[string]interface {}{"uid":"0x186bf"}, "uid":"0x186bd"}}}}
                                actual  : map[string]interface {}{"data":map[string]interface {}{"me":[]interface {}{map[string]interface {}{"onetoonerel":map[string]interface {}{"uid":[]interface {}{"0x186be", "0x186bf"}}, "uid":"0x186bd"}}}}
                                --- Expected
                                +++ Actual
                                @@ -5,3 +5,6 @@
                                     (string) (len=11) "onetoonerel": (map[string]interface {}) (len=1) {
                                -     (string) (len=3) "uid": (string) (len=7) "0x186bf"
                                +     (string) (len=3) "uid": ([]interface {}) (len=2) {
                                +      (string) (len=7) "0x186be",
                                +      (string) (len=7) "0x186bf"
                                +     }
                Test:           TestOverwriteOneToOneRelationInATransaction

aakside commented :

I’m looking into this.

martinmr commented :

I will look into this. But in version 1.2.2 you should be able to overwrite the value with a single set. Can you try doing just the set instead of delete+ set? You don’t need the delete anymore. I’ll check the documentation to see if that’s been updated.

There are tests for this use case but I am guessing there are no tests for the old workflow (delete + add).

This is fixed by this PR: https://github.com/dgraph-io/dgraph/pull/6431

We have released Dgraph v1.2.8 that has the fix for this issue