Updating graph using struct with uid makes edges disappear

Moved from GitHub dgo/130

Posted by AugustDev:

I am creating a node by serializing struct and feeding to dgraph. Then I would like to update a value node of the graph by building go struct again and providing it with node UID. Even though update is successful, some edges have disappeared.

Dgo go documentation says While setting an object if a struct has a Uid then its properties in the graph are updated else a new node is created.

I am providing code which:

  1. Creates User with FavQuote, FavCar and Contact details. (All good)
  2. Knowing UID of User I update FavQuote. (FavQuote updated, FavCar remains, however edge to Contact details disappeared)

I had no problems with such node updates before, however this time the struct is more deeply nested.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/dgraph-io/dgo/v200"
	"github.com/dgraph-io/dgo/v200/protos/api"
	"google.golang.org/grpc"
)

// User -
type User struct {
	UID            string             `json:"uid,omitempty"`
	DType          []string           `json:"dgraph.type,omitempty"`
	FavQuote       string             `json:"quote,omitempty"`
	FavCar         string             `json:"car,omitempty"`
	ContactDetails UserContactDetails `json:"user.contact_details,omitempty"`
}

// UserContactDetails -
type UserContactDetails struct {
	UID    string      `json:"uid,omitempty"`
	DType  []string    `json:"dgraph.type,omitempty"`
	Mobile PhoneNumber `json:"contact_details.mobile,omitempty"`
}

// PhoneNumber -
type PhoneNumber struct {
	UID            string   `json:"uid,omitempty"`
	DType          []string `json:"dgraph.type,omitempty"`
	CountryCode    string   `json:"phone.country_code,omitempty"`
	NationalNumber string   `json:"phone.national_number,omitempty"`
}

func main() {
	conn, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))

	u := User{
		UID:      "_:newUser",
		DType:    []string{"User"},
		FavQuote: "Moon",
		FavCar:   "Lambo",
		ContactDetails: UserContactDetails{
			DType: []string{"ContactDetails"},
			Mobile: PhoneNumber{
				DType:          []string{"PhoneNumber"},
				CountryCode:    "+33",
				NationalNumber: "98766543",
			},
		},
	}

	op := &api.Operation{}
	op.Schema = `
		<phone.country_code>: string @index(exact) .
		<phone.national_number>: string @index(exact) .
		<quote>: string .
		<car>: string .

		type User {
			quote
			car
			user.contact_details: ContactDetails
		}

		type ContactDetails {
			contact_details.mobile: PhoneNumber
		}

		type PhoneNumber {
			phone.country_code
			phone.national_number
		}
	`

	ctx := context.Background()
	if err := dg.Alter(ctx, op); err != nil {
		log.Fatal(err)
	}

	// CREATING USER
	mu := &api.Mutation{
		CommitNow: true,
	}

	ub, err := json.Marshal(u)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = ub
	response, err := dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	uid := response.Uids["newUser"]
	fmt.Println("UID: " + uid)

	// User correctly created with all details and can be verified in Ratel

	// MODIFYING USER
	u = User{
		UID:      uid,
		FavQuote: "Jupiter",
	}

	mu = &api.Mutation{
		CommitNow: true,
	}

	ub, err = json.Marshal(u)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = ub
	_, err = dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	// User updated `FavQuote`. "FavCar" remains however contact details edge from user have dissapeared !?
}

To check data in Ratel I use

{
  u(func: uid(0x2a85)) {
    uid
    quote
    car
    user.contact_details {
      contact_details.mobile {
        phone.country_code
        phone.national_number
      }
    }
  }
}

Graph before modifying user

      {
        "uid": "0x2a85",
        "quote": "Moon",
        "car": "Lambo",
        "user.contact_details": {
          "contact_details.mobile": {
            "phone.country_code": "+33",
            "phone.national_number": "98766543"
          }
        }
      }

Graph after modifying user

      {
        "uid": "0x2a85",
        "quote": "Jupiter",
        "car": "Lambo"
      }

Which no longer has contact details :man_shrugging:

AugustDev commented :

Aaa solved. Someone pointed out that problem was because of the way Go serialiazes structs. I had to replace UserContactDetails to * UserContactDetails and it all works. Thank you kind stranger