dgo

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2019 License: Apache-2.0 Imports: 11 Imported by: 189

README

dgo GoDoc Build Status

Official Dgraph Go client which communicates with the server using gRPC.

Before using this client, we highly recommend that you go through tour.dgraph.io and docs.dgraph.io to understand how to run and work with Dgraph.

Table of contents

Install

Note that, dgo 1.0.0 works with dgraph 1.0.x only

go get -u -v github.com/dgraph-io/dgo

Using a client

Create a client

dgraphClient object can be initialised by passing it a list of api.DgraphClient clients as variadic arguments. Connecting to multiple Dgraph servers in the same cluster allows for better distribution of workload.

The following code snippet shows just one connection.

conn, err := grpc.Dial("localhost:9080", grpc.WithInsecure())
if err != nil {
  log.Fatal(err)
}
defer conn.Close()
dgraphClient := dgo.NewDgraphClient(api.NewDgraphClient(conn))
Alter the database

To set the schema, create an instance of api.Operation and use the Alter endpoint.

op := &api.Operation{
  Schema: `name: string @index(exact) .`,
}
err := dgraphClient.Alter(ctx, op)
// Check error

Operation contains other fields as well, including DropAttr and DropAll. DropAll is useful if you wish to discard all the data, and start from a clean slate, without bringing the instance down. DropAttr is used to drop all the data related to a predicate.

Create a transaction

To create a transaction, call dgraphClient.NewTxn(), which returns a *dgo.Txn object. This operation incurs no network overhead.

It is a good practice to call txn.Discard() using a defer statement after it is initialized. Calling txn.Discard() after txn.Commit() is a no-op and you can call txn.Discard() multiple times with no additional side-effects.

txn := dgraphClient.NewTxn()
defer txn.Discard(ctx)

Read-only transactions can be created by calling c.NewReadOnlyTxn(). Read-only transactions are useful to increase read speed because they can circumvent the usual consensus protocol. Read-only transactions cannot contain mutations and trying to call txn.Commit() will result in an error. Calling txn.Discard() will be a no-op.

Run a mutation

txn.Mutate(ctx, mu) runs a mutation. It takes in a context.Context and a *api.Mutation object. You can set the data using JSON or RDF N-Quad format.

To use JSON, use the fields SetJson and DeleteJson, which accept a string representing the nodes to be added or removed respectively (either as a JSON map or a list). To use RDF, use the fields SetNquads and DeleteNquads, which accept a string representing the valid RDF triples (one per line) to added or removed respectively. This protobuf object also contains the Set and Del fields which accept a list of RDF triples that have already been parsed into our internal format. As such, these fields are mainly used internally and users should use the SetNquads and DeleteNquads instead if they are planning on using RDF.

We define a Person struct to represent a Person and marshal an instance of it to use with Mutation object.

type Person struct {
  Uid  string `json:"uid,omitempty"`
  Name string `json:"name,omitempty"`
}

p := Person{
  Uid:  "_:alice",
  Name: "Alice",
}

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

mu := &api.Mutation{
  SetJson: pb,
}
assigned, err := txn.Mutate(ctx, mu)
if err != nil {
  log.Fatal(err)
}

For a more complete example, see GoDoc.

Sometimes, you only want to commit a mutation, without querying anything further. In such cases, you can use mu.CommitNow = true to indicate that the mutation must be immediately committed.

Run a query

You can run a query by calling txn.Query(ctx, q). You will need to pass in a GraphQL+- query string. If you want to pass an additional map of any variables that you might want to set in the query, call txn.QueryWithVars(ctx, q, vars) with the variables map as third argument.

Let's run the following query with a variable $a:

q := `query all($a: string) {
    all(func: eq(name, $a)) {
      name
    }
  }`

resp, err := txn.QueryWithVars(ctx, q, map[string]string{"$a": "Alice"})
fmt.Println(string(resp.Json))

When running a schema query, the schema response is found in the Schema field of api.Response.

q := `schema(pred: [name]) {
  type
  index
  reverse
  tokenizer
  list
  count
  upsert
  lang
}`

resp, err := txn.Query(ctx, q)
fmt.Println(resp.Schema)
Commit a transaction

A transaction can be committed using the txn.Commit(ctx) method. If your transaction consisted solely of calls to txn.Query or txn.QueryWithVars, and no calls to txn.Mutate, then calling txn.Commit is not necessary.

An error will be returned if other transactions running concurrently modify the same data that was modified in this transaction. It is up to the user to retry transactions when they fail.

txn := dgraphClient.NewTxn()
// Perform some queries and mutations.

err := txn.Commit(ctx)
if err == y.ErrAborted {
  // Retry or handle error
}
Setting Metadata Headers

Metadata headers such as authentication tokens can be set through the context of gRPC methods. Below is an example of how to set a header named "auth-token".

// The following piece of code shows how one can set metadata with
// auth-token, to allow Alter operation, if the server requires it.
md := metadata.New(nil)
md.Append("auth-token", "the-auth-token-value")
ctx := metadata.NewOutgoingContext(context.Background(), md)
dg.Alter(ctx, &op)

Development

Running tests

Make sure you have dgraph installed before you run the tests. This script will run the unit and integration tests.

go test -v ./...

Documentation

Overview

Package dgo is used to interact with a Dgraph server. Queries, mutations, and most other types of admin tasks can be run from the client.

Example (GetSchema)
package main

import (
	"context"
	"fmt"
	"log"

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

func main() {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}
	defer conn.Close()

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)

	op := &api.Operation{}
	op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		loc: geo .
		dob: datetime .
	`

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

	// Ask for the type of name and age.
	resp, err := dg.NewTxn().Query(ctx, `schema(pred: [name, age]) {type}`)
	if err != nil {
		log.Fatal(err)
	}

	// resp.Json contains the schema query response.
	fmt.Println(string(resp.Json))
}
Output:

{"schema":[{"predicate":"age","type":"int"},{"predicate":"name","type":"string"}]}
Example (SetObject)
package main

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

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

type School struct {
	Name string `json:"name,omitempty"`
}

type loc struct {
	Type   string    `json:"type,omitempty"`
	Coords []float64 `json:"coordinates,omitempty"`
}

// If omitempty is not set, then edges with empty values (0 for int/float, "" for string, false
// for bool) would be created for values not specified explicitly.

type Person struct {
	Uid      string     `json:"uid,omitempty"`
	Name     string     `json:"name,omitempty"`
	Age      int        `json:"age,omitempty"`
	Dob      *time.Time `json:"dob,omitempty"`
	Married  bool       `json:"married,omitempty"`
	Raw      []byte     `json:"raw_bytes,omitempty"`
	Friends  []Person   `json:"friend,omitempty"`
	Location loc        `json:"loc,omitempty"`
	School   []School   `json:"school,omitempty"`
}

func main() {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}
	defer conn.Close()

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)

	dob := time.Date(1980, 01, 01, 23, 0, 0, 0, time.UTC)
	// While setting an object if a struct has a Uid then its properties in the graph are updated
	// else a new node is created.
	// In the example below new nodes for Alice, Bob and Charlie and school are created (since they
	// dont have a Uid).
	p := Person{
		Uid:     "_:alice",
		Name:    "Alice",
		Age:     26,
		Married: true,
		Location: loc{
			Type:   "Point",
			Coords: []float64{1.1, 2},
		},
		Dob: &dob,
		Raw: []byte("raw_bytes"),
		Friends: []Person{{
			Name: "Bob",
			Age:  24,
		}, {
			Name: "Charlie",
			Age:  29,
		}},
		School: []School{{
			Name: "Crown Public School",
		}},
	}

	op := &api.Operation{}
	op.Schema = `
		name: string @index(exact) .
		age: int .
		married: bool .
		loc: geo .
		dob: datetime .
	`

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

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	// Assigned uids for nodes which were created would be returned in the assigned.Uids map.
	variables := map[string]string{"$id1": assigned.Uids["alice"]}
	q := `query Me($id1: string){
		me(func: uid($id1)) {
			name
			dob
			age
			loc
			raw_bytes
			married
			friend @filter(eq(name, "Bob")){
				name
				age
			}
			school {
				name
			}
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}
	// fmt.Printf("Me: %+v\n", r.Me)
	// R.Me would be same as the person that we set above.

	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"Alice","dob":"1980-01-01T23:00:00Z","age":26,"loc":{"type":"Point","coordinates":[1.1,2]},"raw_bytes":"cmF3X2J5dGVz","married":true,"friend":[{"name":"Bob","age":24}],"school":[{"name":"Crown Public School"}]}]}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrFinished is returned when an operation is performed on
	// already committed or discarded transaction
	ErrFinished = errors.New("Transaction has already been committed or discarded")
	// ErrReadOnly is returned when a write/update is performed on a readonly transaction
	ErrReadOnly = errors.New("Readonly transaction cannot run mutations or be committed")
)

Functions

func DeleteEdges

func DeleteEdges(mu *api.Mutation, uid string, predicates ...string)

DeleteEdges sets the edges corresponding to predicates on the node with the given uid for deletion. This helper function doesn't run the mutation on the server. Txn needs to be committed in order to execute the mutation.

Example
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	op := &api.Operation{}
	op.Schema = `
			age: int .
			married: bool .
			name: string @lang .
			location: string .
		`

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

	type School struct {
		Uid  string `json:"uid"`
		Name string `json:"name@en,omitempty"`
	}

	type Person struct {
		Uid      string    `json:"uid,omitempty"`
		Name     string    `json:"name,omitempty"`
		Age      int       `json:"age,omitempty"`
		Married  bool      `json:"married,omitempty"`
		Friends  []Person  `json:"friends,omitempty"`
		Location string    `json:"location,omitempty"`
		Schools  []*School `json:"schools,omitempty"`
	}

	// Lets add some data first.
	p := Person{
		Uid:      "_:alice",
		Name:     "Alice",
		Age:      26,
		Married:  true,
		Location: "Riley Street",
		Friends: []Person{{
			Name: "Bob",
			Age:  24,
		}, {
			Name: "Charlie",
			Age:  29,
		}},
		Schools: []*School{&School{
			Name: "Crown Public School",
		}},
	}

	mu := &api.Mutation{}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = pb
	mu.CommitNow = true
	mu.IgnoreIndexConflict = true
	assigned, err := dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	alice := assigned.Uids["alice"]

	variables := make(map[string]string)
	variables["$alice"] = alice
	const q = `query Me($alice: string){
		me(func: uid($alice)) {
			name
			age
			location
			married
			friends {
				name
				age
			}
			schools {
				name@en
			}
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	// Now lets delete the friend and location edge from Alice
	mu = &api.Mutation{}
	dgo.DeleteEdges(mu, alice, "friends", "location")

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

	resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"Alice","age":26,"married":true,"schools":[{"name@en":"Crown Public School"}]}]}

Types

type Dgraph

type Dgraph struct {
	// contains filtered or unexported fields
}

Dgraph is a transaction aware client to a set of Dgraph server instances.

func NewDgraphClient

func NewDgraphClient(clients ...api.DgraphClient) *Dgraph

NewDgraphClient creates a new Dgraph (client) for interacting with Alphas. The client is backed by multiple connections to the same or different servers in a cluster.

A single Dgraph (client) is thread safe for sharing with multiple goroutines.

func (*Dgraph) Alter

func (d *Dgraph) Alter(ctx context.Context, op *api.Operation) error

Alter can be used to do the following by setting various fields of api.Operation:

  1. Modify the schema.
  2. Drop a predicate.
  3. Drop the database.
Example (DropAll)
package main

import (
	"context"
	"log"
	"strings"
	"time"

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	op := api.Operation{DropAll: true}
	ctx := context.Background()
	if err := dg.Alter(ctx, &op); err != nil {
		log.Fatal(err)
	}
}
Output:

func (*Dgraph) Login

func (d *Dgraph) Login(ctx context.Context, userid string, password string) error

Login logs in the current client using the provided credentials. Valid for the duration the client is alive.

func (*Dgraph) NewReadOnlyTxn

func (d *Dgraph) NewReadOnlyTxn() *Txn

NewReadOnlyTxn sets the txn to readonly transaction.

func (*Dgraph) NewTxn

func (d *Dgraph) NewTxn() *Txn

NewTxn creates a new transaction.

type Txn

type Txn struct {
	// contains filtered or unexported fields
}

Txn is a single atomic transaction. A transaction lifecycle is as follows:

  1. Created using NewTxn.
  2. Various Query and Mutate calls made.
  3. Commit or Discard used. If any mutations have been made, It's important that at least one of these methods is called to clean up resources. Discard is a no-op if Commit has already been called, so it's safe to defer a call to Discard immediately after NewTxn.

func (*Txn) BestEffort

func (txn *Txn) BestEffort() *Txn

BestEffort enables best effort in read-only queries. This will ask the Dgraph Alpha to try to get timestamps from memory in a best effort to reduce the number of outbound requests to Zero. This may yield improved latencies in read-bound datasets.

This method will panic if the transaction is not read-only. Returns the transaction itself.

func (*Txn) Commit

func (txn *Txn) Commit(ctx context.Context) error

Commit commits any mutations that have been made in the transaction. Once Commit has been called, the lifespan of the transaction is complete.

Errors could be returned for various reasons. Notably, ErrAborted could be returned if transactions that modify the same data are being run concurrently. It's up to the user to decide if they wish to retry. In this case, the user should create a new transaction.

func (*Txn) Discard

func (txn *Txn) Discard(ctx context.Context) error

Discard cleans up the resources associated with an uncommitted transaction that contains mutations. It is a no-op on transactions that have already been committed or don't contain mutations. Therefore, it is safe (and recommended) to call as a deferred function immediately after a new transaction is created.

In some cases, the transaction can't be discarded, e.g. the grpc connection is unavailable. In these cases, the server will eventually do the transaction clean up itself without any intervention from the client.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()

	ctx, toCancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer toCancel()
	err := dg.Alter(ctx, &api.Operation{
		DropAll: true,
	})
	if err != nil {
		log.Fatal("The drop all operation should have succeeded")
	}

	err = dg.Alter(ctx, &api.Operation{
		Schema: `name: string @index(exact) .`,
	})
	if err != nil {
		log.Fatal("The alter should have succeeded")
	}

	txn := dg.NewTxn()
	_, err = txn.Mutate(ctx, &api.Mutation{
		SetNquads: []byte(`_:a <name> "Alice" .`),
	})
	if err != nil {
		log.Fatal("The mutation should have succeeded")
	}
	txn.Discard(ctx)

	// now query the cluster and make sure that the data has made no effect
	queryTxn := dg.NewReadOnlyTxn()
	query := `
    {
      q (func: eq(name, "Alice")) {
        name
      }
    }`
	resp, err := queryTxn.Query(ctx, query)
	if err != nil {
		log.Fatal("The query should have succeeded")
	}

	fmt.Printf(string(resp.Json))
}
Output:

{"q":[]}

func (*Txn) Mutate

func (txn *Txn) Mutate(ctx context.Context, mu *api.Mutation) (*api.Assigned, error)

Mutate allows data stored on Dgraph instances to be modified. The fields in api.Mutation come in pairs, set and delete. Mutations can either be encoded as JSON or as RDFs.

If CommitNow is set, then this call will result in the transaction being committed. In this case, an explicit call to Commit doesn't need to be made subsequently.

If the mutation fails, then the transaction is discarded and all future operations on it will fail.

Example
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	type School struct {
		Name string `json:"name,omitempty"`
	}

	type loc struct {
		Type   string    `json:"type,omitempty"`
		Coords []float64 `json:"coordinates,omitempty"`
	}

	// If omitempty is not set, then edges with empty values (0 for int/float, "" for string, false
	// for bool) would be created for values not specified explicitly.

	type Person struct {
		Uid      string   `json:"uid,omitempty"`
		Name     string   `json:"name,omitempty"`
		Age      int      `json:"age,omitempty"`
		Married  bool     `json:"married,omitempty"`
		Raw      []byte   `json:"raw_bytes,omitempty"`
		Friends  []Person `json:"friend,omitempty"`
		Location loc      `json:"loc,omitempty"`
		School   []School `json:"school,omitempty"`
	}

	dg, cancel := getDgraphClient()
	defer cancel()
	// While setting an object if a struct has a Uid then its properties in the graph are updated
	// else a new node is created.
	// In the example below new nodes for Alice, Bob and Charlie and school are created (since they
	// don't have a Uid).
	p := Person{
		Uid:     "_:alice",
		Name:    "Alice",
		Age:     26,
		Married: true,
		Location: loc{
			Type:   "Point",
			Coords: []float64{1.1, 2},
		},
		Raw: []byte("raw_bytes"),
		Friends: []Person{{
			Name: "Bob",
			Age:  24,
		}, {
			Name: "Charlie",
			Age:  29,
		}},
		School: []School{{
			Name: "Crown Public School",
		}},
	}

	op := &api.Operation{}
	op.Schema = `
		age: int .
		married: bool .
	`

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

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	// Assigned uids for nodes which were created would be returned in the assigned.Uids map.
	puid := assigned.Uids["alice"]
	const q = `query Me($id: string){
		me(func: uid($id)) {
			name
			age
			loc
			raw_bytes
			married
			friend @filter(eq(name, "Bob")) {
				name
				age
			}
			school {
				name
			}
		}
	}`

	variables := make(map[string]string)
	variables["$id"] = puid
	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	// R.Me would be same as the person that we set above.
	// fmt.Printf("Me: %+v\n", r.Me)

	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"Alice","age":26,"loc":{"type":"Point","coordinates":[1.1,2]},"raw_bytes":"cmF3X2J5dGVz","married":true,"friend":[{"name":"Bob","age":24}],"school":[{"name":"Crown Public School"}]}]}
Example (Bytes)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	type Person struct {
		Uid   string `json:"uid,omitempty"`
		Name  string `json:"name,omitempty"`
		Bytes []byte `json:"bytes,omitempty"`
	}

	op := &api.Operation{}
	op.Schema = `
		name: string @index(exact) .
	`

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

	p := Person{
		Name:  "Alice-new",
		Bytes: []byte("raw_bytes"),
	}

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	q := `{
	q(func: eq(name, "Alice-new")) {
		name
		bytes
	}
}`

	resp, err := dg.NewTxn().Query(ctx, q)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"q"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Me: %+v\n", r.Me)

}
Output:

Me: [{Uid: Name:Alice-new Bytes:[114 97 119 95 98 121 116 101 115]}]
Example (DeleteNode)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	// In this test we check S * * deletion.
	type Person struct {
		Uid        string    `json:"uid,omitempty"`
		Name       string    `json:"name,omitempty"`
		Age        int       `json:"age,omitempty"`
		Married    bool      `json:"married,omitempty"`
		Friends    []*Person `json:"friend,omitempty"`
		DgraphType string    `json:"dgraph.type,omitempty"`
	}

	p := Person{
		Uid:        "_:alice",
		Name:       "Alice",
		Age:        26,
		Married:    true,
		DgraphType: "Person",
		Friends: []*Person{&Person{
			Uid:  "_:bob",
			Name: "Bob",
			Age:  24,
		}, &Person{
			Uid:  "_:charlie",
			Name: "Charlie",
			Age:  29,
		}},
	}

	op := &api.Operation{}
	op.Schema = `
		age: int .
		married: bool .
        type Person {
          name: string
          age: int
          married: bool
          friend: [uid]
        }
	`

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

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	alice := assigned.Uids["alice"]
	bob := assigned.Uids["bob"]
	charlie := assigned.Uids["charlie"]

	variables := make(map[string]string)
	variables["$alice"] = alice
	variables["$bob"] = bob
	variables["$charlie"] = charlie
	const q = `query Me($alice: string, $bob: string, $charlie: string){
		me(func: uid($alice)) {
			name
			age
			married
			friend {
				uid
				name
				age
			}
		}

		me2(func: uid($bob)) {
			name
			age
		}

		me3(func: uid($charlie)) {
			name
			age
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me  []Person `json:"me"`
		Me2 []Person `json:"me2"`
		Me3 []Person `json:"me3"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)

	// Now lets try to delete Alice. This won't delete Bob and Charlie but just remove the
	// connection between Alice and them.

	// The JSON for deleting a node should be of the form {"uid": "0x123"}. If you wanted to
	// delete multiple nodes you could supply an array of objects like [{"uid": "0x321"}, {"uid":
	// "0x123"}] to DeleteJson.

	d := map[string]string{"uid": alice}
	pb, err = json.Marshal(d)
	if err != nil {
		log.Fatal(err)
	}

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

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

	resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Resp after deleting node: %+v\n", string(resp.Json))
}
Output:

Resp after deleting node: {"me":[],"me2":[{"name":"Bob","age":24}],"me3":[{"name":"Charlie","age":29}]}
Example (DeletePredicate)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	type Person struct {
		Uid     string   `json:"uid,omitempty"`
		Name    string   `json:"name,omitempty"`
		Age     int      `json:"age,omitempty"`
		Married bool     `json:"married,omitempty"`
		Friends []Person `json:"friend,omitempty"`
	}

	p := Person{
		Uid:     "_:alice",
		Name:    "Alice",
		Age:     26,
		Married: true,
		Friends: []Person{Person{
			Name: "Bob",
			Age:  24,
		}, Person{
			Name: "Charlie",
			Age:  29,
		}},
	}

	op := &api.Operation{}
	op.Schema = `
		age: int .
		married: bool .
	`

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

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	alice := assigned.Uids["alice"]

	variables := make(map[string]string)
	variables["$id"] = alice
	const q = `query Me($id: string){
		me(func: uid($id)) {
			name
			age
			married
			friend {
				uid
				name
				age
			}
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}
	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	op = &api.Operation{DropAttr: "friend"}
	err = dg.Alter(ctx, op)
	if err != nil {
		log.Fatal(err)
	}

	op = &api.Operation{DropAttr: "married"}
	err = dg.Alter(ctx, op)
	if err != nil {
		log.Fatal(err)
	}

	// Also lets run the query again to verify that predicate data was deleted.
	resp, err = dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	r = Root{}
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	// Alice should have no friends and only two attributes now.
	fmt.Printf("Response after deletion: %+v\n", r)
}
Output:

Response after deletion: {Me:[{Uid: Name:Alice Age:26 Married:false Friends:[]}]}
Example (Facets)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	// Doing a dropAll isn't required by the user. We do it here so that we can verify that the
	// example runs as expected.
	op := api.Operation{DropAll: true}
	ctx := context.Background()
	if err := dg.Alter(ctx, &op); err != nil {
		log.Fatal(err)
	}

	op = api.Operation{}
	op.Schema = `
		name: string @index(exact) .
	`

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

	// This example shows example for SetObject using facets.
	type School struct {
		Name  string    `json:"name,omitempty"`
		Since time.Time `json:"school|since,omitempty"`
	}

	type Person struct {
		Uid        string   `json:"uid,omitempty"`
		Name       string   `json:"name,omitempty"`
		NameOrigin string   `json:"name|origin,omitempty"`
		Friends    []Person `json:"friend,omitempty"`

		// These are facets on the friend edge.
		Since  time.Time `json:"friend|since,omitempty"`
		Family string    `json:"friend|family,omitempty"`
		Age    float64   `json:"friend|age,omitempty"`
		Close  bool      `json:"friend|close,omitempty"`

		School []School `json:"school,omitempty"`
	}

	ti := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	p := Person{
		Uid:        "_:alice",
		Name:       "Alice",
		NameOrigin: "Indonesia",
		Friends: []Person{
			Person{
				Name:   "Bob",
				Since:  ti,
				Family: "yes",
				Age:    13,
				Close:  true,
			},
			Person{
				Name:   "Charlie",
				Family: "maybe",
				Age:    16,
			},
		},
		School: []School{School{
			Name:  "Wellington School",
			Since: ti,
		}},
	}

	mu := &api.Mutation{}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = pb
	mu.CommitNow = true
	assigned, err := dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	auid := assigned.Uids["alice"]
	variables := make(map[string]string)
	variables["$id"] = auid

	const q = `query Me($id: string){
        me(func: uid($id)) {
            name @facets
			friend @filter(eq(name, "Bob")) @facets {
                name
            }
            school @facets {
                name
            }

        }
    }`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Me: %+v\n", r.Me)
}
Output:

Me: [{Uid: Name:Alice NameOrigin:Indonesia Friends:[{Uid: Name:Bob NameOrigin: Friends:[] Since:2009-11-10 23:00:00 +0000 UTC Family:yes Age:13 Close:true School:[]}] Since:0001-01-01 00:00:00 +0000 UTC Family: Age:0 Close:false School:[{Name:Wellington School Since:2009-11-10 23:00:00 +0000 UTC}]}]
Example (List)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel() // This example shows example for SetObject for predicates with list type.
	type Person struct {
		Uid         string   `json:"uid"`
		Address     []string `json:"address"`
		PhoneNumber []int64  `json:"phone_number"`
	}

	p := Person{
		Address:     []string{"Redfern", "Riley Street"},
		PhoneNumber: []int64{9876, 123},
	}

	op := &api.Operation{}
	op.Schema = `
		address: [string] .
		phone_number: [int] .
	`
	ctx := context.Background()
	err := dg.Alter(ctx, op)
	if err != nil {
		log.Fatal(err)
	}

	mu := &api.Mutation{}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = pb
	mu.CommitNow = true
	assigned, err := dg.NewTxn().Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	variables := map[string]string{"$id": assigned.Uids["blank-0"]}
	const q = `
	query Me($id: string){
		me(func: uid($id)) {
			address
			phone_number
		}
	}
	`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	// List items aren't guaranteed to be in the same order.
	fmt.Println(string(resp.Json))
	// {"me":[{"address":["Riley Street","Redfern"],"phone_number":[9876,123]}]}

}
Output:

Example (Upsert)
package main

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()

	ctx, toCancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer toCancel()

	// Warn: Cleaning up the database
	if err := dg.Alter(ctx, &api.Operation{DropAll: true}); err != nil {
		log.Fatal("The drop all operation should have succeeded")
	}

	op := &api.Operation{}
	op.Schema = `
		name: string .
		email: string @index(exact) .
	`
	if err := dg.Alter(ctx, op); err != nil {
		log.Fatal(err)
	}

	m1 := `
		_:n1 <name> "user" .
		_:n1 <email> "user@dgraphO.io" .
`
	mu := &api.Mutation{
		SetNquads: []byte(m1),
		CommitNow: true,
	}
	if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
		log.Fatal(err)
	}

	mu.Query = `
		query {
  			me(func: eq(email, "user@dgraphO.io")) {
	    		v as uid
  			}
		}
	`
	m2 := `uid(v) <email> "user@dgraph.io" .`
	mu.SetNquads = []byte(m2)

	// Update email only if matching uid found.
	if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
		log.Fatal(err)
	}

	query := `
		{
			me(func: eq(email, "user@dgraph.io")) {
				name
				email
			}
		}
	`
	resp, err := dg.NewTxn().Query(ctx, query)
	if err != nil {
		log.Fatal(err)
	}

	// resp.Json contains the updated value.
	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"user","email":"user@dgraph.io"}]}
Example (UpsertJSON)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()

	// Warn: Cleaning up the database
	ctx := context.Background()
	if err := dg.Alter(ctx, &api.Operation{DropAll: true}); err != nil {
		log.Fatal(err)
	}

	type Person struct {
		Uid     string   `json:"uid,omitempty"`
		Name    string   `json:"name,omitempty"`
		Age     int      `json:"age,omitempty"`
		Email   string   `json:"email,omitempty"`
		Friends []Person `json:"friend,omitempty"`
	}

	op := &api.Operation{Schema: `email: string @index(exact) @upsert .`}
	if err := dg.Alter(context.Background(), op); err != nil {
		log.Fatal(err)
	}

	// Create and query the user using Upsert block
	mu := &api.Mutation{CommitNow: true}
	mu.Query = `
		{
			me(func: eq(email, "user@dgraph.io")) {
				...fragmentA
			}
		}

		fragment fragmentA {
			v as uid
		}
	`
	pb, err := json.Marshal(Person{Uid: "uid(v)", Name: "Wrong", Email: "user@dgraph.io"})
	if err != nil {
		log.Fatal(err)
	}
	mu.SetJson = pb
	if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
		log.Fatal(err)
	}

	// Fix the name and add age
	pb, err = json.Marshal(Person{Uid: "uid(v)", Name: "user", Age: 35})
	if err != nil {
		log.Fatal(err)
	}
	mu.SetJson = pb
	if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
		log.Fatal(err)
	}

	q := `
  		{
			Me(func: has(email)) {
				age
				name
				email
			}
		}
	`
	resp, err := dg.NewReadOnlyTxn().Query(ctx, q)
	if err != nil {
		log.Fatal("The query should have succeeded")
	}

	type Root struct {
		Me []Person `json:"me"`
	}
	var r Root
	if err := json.Unmarshal(resp.Json, &r); err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(resp.Json))

	// Delete the user now
	mu.SetJson = nil
	dgo.DeleteEdges(mu, "uid(v)", "age", "name", "email")
	if _, err := dg.NewTxn().Mutate(ctx, mu); err != nil {
		log.Fatal(err)
	}

	resp, err = dg.NewReadOnlyTxn().Query(ctx, q)
	if err != nil {
		log.Fatal("The query should have succeeded")
	}
	if err := json.Unmarshal(resp.Json, &r); err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(resp.Json))
}
Output:

{"Me":[{"age":35,"name":"user","email":"user@dgraph.io"}]}
{"Me":[]}

func (*Txn) Query

func (txn *Txn) Query(ctx context.Context, q string) (*api.Response, error)

Query sends a query to one of the connected Dgraph instances. If no mutations need to be made in the same transaction, it's convenient to chain the method, e.g. NewTxn().Query(ctx, "...").

Example (Besteffort)
package main

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()

	// NOTE: Best effort only works with read-only queries.
	txn := dg.NewReadOnlyTxn().BestEffort()
	resp, err := txn.Query(context.Background(), `{ q(func: uid(0x1)) { uid } }`)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(resp.Json))
}
Output:

{"q":[{"uid":"0x1"}]}
Example (Unmarshal)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	type School struct {
		Name string `json:"name,omitempty"`
	}

	type Person struct {
		Uid     string   `json:"uid,omitempty"`
		Name    string   `json:"name,omitempty"`
		Age     int      `json:"age,omitempty"`
		Married bool     `json:"married,omitempty"`
		Raw     []byte   `json:"raw_bytes,omitempty"`
		Friends []Person `json:"friend,omitempty"`
		School  []School `json:"school,omitempty"`
	}

	dg, cancel := getDgraphClient()
	defer cancel()
	op := &api.Operation{}
	op.Schema = `
		age: int .
		married: bool .
	`

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

	p := Person{
		Uid:  "_:bob",
		Name: "Bob",
		Age:  24,
	}

	txn := dg.NewTxn()
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu := &api.Mutation{
		CommitNow: true,
		SetJson:   pb,
	}
	assigned, err := txn.Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}
	bob := assigned.Uids["bob"]

	// While setting an object if a struct has a Uid then its properties in the graph are updated
	// else a new node is created.
	// In the example below new nodes for Alice and Charlie and school are created (since they dont
	// have a Uid).  Alice is also connected via the friend edge to an existing node Bob.
	p = Person{
		Uid:     "_:alice",
		Name:    "Alice",
		Age:     26,
		Married: true,
		Raw:     []byte("raw_bytes"),
		Friends: []Person{{
			Uid: bob,
		}, {
			Name: "Charlie",
			Age:  29,
		}},
		School: []School{{
			Name: "Crown Public School",
		}},
	}

	txn = dg.NewTxn()
	mu = &api.Mutation{}
	pb, err = json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

	mu.SetJson = pb
	mu.CommitNow = true
	assigned, err = txn.Mutate(ctx, mu)
	if err != nil {
		log.Fatal(err)
	}

	// Assigned uids for nodes which were created would be returned in the assigned.Uids map.
	puid := assigned.Uids["alice"]
	variables := make(map[string]string)
	variables["$id"] = puid
	const q = `query Me($id: string){
		me(func: uid($id)) {
			name
			age
			loc
			raw_bytes
			married
			friend @filter(eq(name, "Bob")) {
				name
				age
			}
			school {
				name
			}
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"Alice","age":26,"raw_bytes":"cmF3X2J5dGVz","married":true,"friend":[{"name":"Bob","age":24}],"school":[{"name":"Crown Public School"}]}]}
Example (Variables)
package main

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

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

type CancelFunc func()

func getDgraphClient() (*dgo.Dgraph, CancelFunc) {
	conn, err := grpc.Dial("127.0.0.1:9180", grpc.WithInsecure())
	if err != nil {
		log.Fatal("While trying to dial gRPC")
	}

	dc := api.NewDgraphClient(conn)
	dg := dgo.NewDgraphClient(dc)
	ctx := context.Background()

	for {

		err = dg.Login(ctx, "groot", "password")
		if err == nil || !strings.Contains(err.Error(), "Please retry") {
			break
		}
		time.Sleep(time.Second)
	}
	if err != nil {
		log.Fatalf("While trying to login %v", err.Error())
	}

	return dg, func() {
		if err := conn.Close(); err != nil {
			log.Printf("Error while closing connection:%v", err)
		}
	}
}

func main() {
	dg, cancel := getDgraphClient()
	defer cancel()
	type Person struct {
		Uid  string `json:"uid,omitempty"`
		Name string `json:"name,omitempty"`
	}

	op := &api.Operation{}
	op.Schema = `
		name: string @index(exact) .
	`

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

	p := Person{
		Name: "Alice",
	}

	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}

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

	variables := make(map[string]string)
	variables["$a"] = "Alice"
	q := `query Alice($a: string){
		me(func: eq(name, $a)) {
			name
		}
	}`

	resp, err := dg.NewTxn().QueryWithVars(ctx, q, variables)
	if err != nil {
		log.Fatal(err)
	}

	type Root struct {
		Me []Person `json:"me"`
	}

	var r Root
	err = json.Unmarshal(resp.Json, &r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(resp.Json))
}
Output:

{"me":[{"name":"Alice"}]}

func (*Txn) QueryWithVars

func (txn *Txn) QueryWithVars(ctx context.Context, q string, vars map[string]string) (
	*api.Response, error)

QueryWithVars is like Query, but allows a variable map to be used. This can provide safety against injection attacks.

func (*Txn) Sequencing

func (txn *Txn) Sequencing(sequencing api.LinRead_Sequencing)

Sequencing is no longer used

Directories

Path Synopsis
protos
api
x
y
Package y contains the code shared by the Go client and Dgraph server.
Package y contains the code shared by the Go client and Dgraph server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL