When I insert new data, how do I use the Golang client to correlate existing nodes

When I insert new data, how do I verify it first, then decide whether to insert a new one or before it is modified.
For example:
I already have a node:

company
{
_:A <name> "Dgraph" .
_:A <companyName> "Dgraph Company"
_:A <info> "Big Data Company"
}
person
{
_:B <name> "Alic " .
_:B <myCompany> _:A
}

 email
{
_:C <name> "A@mail.com".
_:C <owner> _:b .
_:C <mail> "A@mail.com "
}

But then, I received the new JsonData need add to dgraph:

{
"name":Alic 
"email":"A@mail.com"
"emailpassword":"12138"
}

How can i use golang client merge the new data to the nodes? My idea is query first after that -->insert
But I have no idea with the golang client code。And how do I correlate existing data through Golang?
I didn’t find any relevant examples.
Can you write a complete example for me?

Can someone help me?

Finally, I found the solution, as follows:

golang client struct

type A struct {
Uid string
Name  string
Info  string
}

All struct must have Uid
through Uid update data and edge

1 Like

Hey guys,
I have the same problem. I have no idea how to match an existing node.
I can use uid but does it mean that I have my manage uuid myself and store relation like name → uid somewhere else? Every time when I try to add a new node the node becomes duplicated in my database.

Or the solution could be “read befor write”, should i check if a node exists in the database and then use the uid? but it doesn’t make sense. I guess for graphs this is like a standard operation to refer existing node but it seems that I have to do it myself? Am I right?

Thanks,

Yeah, as answered in the other post, uuid is an external id and is like any other string predicate. Dgraph doesn’t interpret it in a special manner. You’d have to do the read before write for now.

my golang client
exp:
first instert base data

 package main

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

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

type A struct {
	Uid  string `json:"uid,omitempty"`
	Name string `json:"testname,omitempty"`
}
type B struct {
	Uid  string `json:"uid,omitempty"`
	Name string `json:"testname,omitempty"`
	In   []A    `json:"In,omitempty"`
}

func main() {

	var a A
	var aa A
	var b B
	a.Name = "test-1a"
	aa.Name = "test-1aa"
	b.Name = "test-1b"
	b.In = append(b.In, a)

	conn, err := grpc.Dial("127.0.0.1:9080", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}
	defer conn.Close()
	dc := api.NewDgraphClient(conn)
	dg := client.NewDgraphClient(dc)
	op := &api.Operation{}
	op.Schema = `
	testname: string @index(exact) . 
	In: uid @reverse .
`
	ctx := context.Background()
	err = dg.Alter(ctx, op)
	if err != nil {
		log.Fatal(err)
	}
	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(b)
	if err != nil {

		log.Fatal(err)
	}

	mu.SetJson = pb
	_, err = dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}
	variables := map[string]string{"$testname": "test-1b"}
	q := `query Me($testname: string){
	me(func: eq(testname,$testname)) {
		  uid
	}
}`
	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}
	type Root struct {
		Me []B `json:"me"`
	}
	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {

		log.Fatal(err)
	}
	fmt.Println(string(resp.Json))
}


result:
41

insert New data connect to base data test-1b

package main

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

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

type A struct {
	Uid  string `json:"uid,omitempty"`
	Name string `json:"testname,omitempty"`
}
type B struct {
	Uid  string `json:"uid,omitempty"`
	Name string `json:"testname,omitempty"`
	In   []A    `json:"In,omitempty"`
}

func main() {

	var aa A
	var b B

	aa.Name = "test-1aa"
	b.Name = "test-1b"
	b.Uid = "0x2738"
	b.In = append(b.In, aa)

	conn, err := grpc.Dial("127.0.0.1:9080", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}
	defer conn.Close()
	dc := api.NewDgraphClient(conn)
	dg := client.NewDgraphClient(dc)

	ctx := context.Background()
	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(b)
	if err != nil {

		log.Fatal(err)
	}

	mu.SetJson = pb
	_, err = dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}
	variables := map[string]string{"$testname": "test-1b"}
	q := `query Me($testname: string){
	me(func: eq(testname,$testname)) {
		  expand(_all_){
			 expand(_all_)}
	}
}`
	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}
	type Root struct {
		Me []B `json:"me"`
	}
	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {

		log.Fatal(err)
	}
	fmt.Println(string(resp.Json))
}

result:
32
The new data “”test-1aa“” already in the base data test-1b,
Just modifying and updates by struct’s Uid

Yes, must read befor write !

@ogreso thank you for your examples, but it can’t help me. the client code can’t be scaled. it works only when you have one client and execute all reads and writes only from one goroutine.

Can you elaborate on what makes you say this? You would encounter transaction conflicts if concurrent operations are trying to modify the same data. That is how transactions work. There would be no conflicts if they are trying to modify different data.

The same data can only be operated in one tnx one time.

@pawan @ogreso The problem is very simple. Let’s say that I have two clients(microservices) connected to the dgraph. My nodes are linked by relation parent-child. Now I send two request to two diffrent services, the first one A(parent) - B(child), the second A(parent) - C(child). in this configuration how should I provide synchronization that the node A will be create only once? I can’t use my uid, so from the dgraph I can get two different uids that point to two different nodes. The thing is that my code has to provide data consistency or maybe I missed something? My point is that with the current version I need a single point when I map uid to nodes.

You can query using the uuid for A or B and then mutate accordingly. In fact, transactions protect you from creating duplicate nodes in this case.

1、Query A through A’s unique attribute,Does the node exist
2、get A‘s’ uid through 1 And mutate

ps: A must have a unique attribute

@pawan Are you telling that when I have one pending transaction the another one wont be commited, how the second tx can now know about the first one. In my scenario both microservices can query for the same node like A and get response that a node doesn’t exist and try to cretae a new one. So how the transaction can protect it? I guess at the end I get to different nodes.

Dgraph checks for write conflicts among different concurrent transactions so as long as you are checking for your errors, you won’t get different nodes. Also, read about upsert you would probably need that directive on the predicate you are upserting against. We also have some examples on how to do this kind of operation at dgraph/contrib/integration/acctupsert/main.go at master · dgraph-io/dgraph · GitHub.

@pawan thanks, will do.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.