Store err with geo and map[string]interface{}

Moved from GitHub dgo/72

Posted by drwpeng:

There is a map[string]interface{} in structs. If I add “data: geo .” to schema:

  • if there is no data in the dgraph:
    This will not be able to save data and no error message
  • if there is data in the dgraph:
    rpc error: code = unknown desc = Schema change not allowed from scalar to uid or vice versa while there is data for pred: data

My test case as follows:

package main

import (
	"context"
	"encoding/json"
	"github.com/fatih/structs"
	"github.com/dgraph-io/dgo"
	"github.com/dgraph-io/dgo/protos/api"
	"google.golang.org/grpc"
	"log"
)

type Animal struct {
	Id   string `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
	Info string `json:"info,omitempty"`
	Size string `json:"size,omitempty"`
}

type PResult struct {
	ID       string                 `json:"id"`
	Name     string                 `json:"name,omitempty"`
	Category string                 `json:"category,omitempty"`
	Data     map[string]interface{} `json:"data,omitempty"`
}

func main() {
	conn, _ := grpc.Dial("localhost:9080", grpc.WithInsecure())
	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))

	ani := Animal{
		Id:   "12345",
		Name: "Tom",
		Info: "dog",
		Size: "10kg",
	}
	pr := PResult{
		ID:       "f11111",
		Name:     "animal",
		Category: "friend",
		Data:     structs.Map(ani),
	}

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

	ctx := context.Background()
	if err := dg.Alter(ctx, op); err != nil {
		log.Fatal(err)
	}
	mu := &api.Mutation{
		CommitNow: true,
	}
	pb, _ := json.Marshal(pr)
	mu.SetJson = pb
	_, _ = dg.NewTxn().Mutate(ctx, mu)
	//	fmt.Println(assign.Uids["blank-0"])
}

campoy commented :

I’m not sure I follow the issue.
On the schema you set data to be of type geo, but then you’re passing a map[string]interface{}.

What’s the goal of this?

If you want to store a map[string]interface{} you are technically creating a new node with its own edges, so the schema should say that data is of type uid.

I just did this on Ratel and it worked.

<category>: string .
<data>: uid .
<id>: string @index(exact) .
<info>: default .
<name>: string .
<size>: default .

Your mutation would be akin to the following:

{
set {
  _:a <id> "f111111" .
  _:a <name> "animal" .
  _:a <category> "friend" .
  _:a <data> _:b .
  _:b <id> "12345" .
  _:b <name> "Tom" .
  _:b <info> "dog" .
  _:b <size> "10kg" .
}
}

And then a simple query like this will retrieve all the data.

{
  q(func: has(data)) {
    id
    name
    category
    data {
      id
      name
      info
      size
    }
  }
}

If your schema already declares data as type uid and you send a query trying to alter the schema to geo you will get the error you mention:

I’ll close the issue, but feel free to reopen if you have any other questions or concerns.

drwpeng commented :

That’s all.
I don’t know there is a uid type, so I mistakenly used geo.
Thank you very much.