Rpc error: code = Unknown desc = Input for predicate author of type uid is scalar

Hello, I’m still very new to Dgraph, so I might be doing something completely wrong…

Basically I have the following schema:

board: uid @reverse .
title: string @index(term, fulltext) .
description: string .
author: uid @reverse .
username: string @index(exact) .

With a User and a Board struct:

type User struct {
	Uid      string `json:"uid,omitempty"`
	Username string `json:"username,omitempty"`
}

type Board struct {
	Uid         string `json:"uid,omitempty"`
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	Author      string `json:"author,omitempty"`
}

I then create a user like this:

var userForm struct {
        Username string `json:"username"`
}
// unmarshal json from http.Request to userForm
resp, err := database.DgraphMutateSetJson(userForm)
if err != nil {
	fmt.Println(err)
}

This works, and from resp.Uids["blank-0"] I get whatever uid was generated, e.g. 0x4.

The problem now is that I want to associate this author uid with whatever Board I create, e.g.:

var boardForm struct {
		Title       string `json:"title"`
		Description string `json:"description"`
		Author      string `json:"author"`
}
// unmarshal json from http.Request to boardForm
resp, err := database.DgraphMutateSetJson(boardForm)
if err != nil {
	fmt.Println(err)
}

However, this results in the error in the title (rpc error: code = Unknown desc = Input for predicate author of type uid is scalar).

My POST request (that is unmarshalled to boardForm) include the following JSON:

{
	"title":"My Title",
	"description":"My Description",
	"author":"0x4"
}

I’d greatly appreciate help about what I’m doing wrong (regarding the error), as well as tips about how I can improve my schema in order to associate a Board with a User, and a Post with a Board + a User, etc.

Hi, so warning here. I have zero skill with Golang. xD

You are using predicates with lower case start. It’s normal? Is not that different from the way you’re building JSON?

If you are entering something else in the “Author stringjson: "author"” field it will return this error that you mention.

Try to create a log of what is being written in the mutation. Just to have an idea that JSON is going correctly. only 0x4 can be written.

Hello, I’m not sure if it’s normal or not, but I saw other projects on GitHub do like this, so I assume it’s normal? I tried capitalize it but still give same error.

I’ve also verified that only 0x4 is being written. Have other ideas about what might be causing it (: ?

Hi, are you using Dgo?

It seems to me that the construction of your JSON is not the same as this example using the official Go client of Dgraph.

see this link

Yeah, and I’m also able to insert and retrieve data (and it appears at localhost:8000). It only becomes a problem when I try to insert another Uid.

You mean Ratel (Dgraph UI)

What you mean?

If you’re using Dgo, I recommend you to build your JSON as the example from the example test in that link above. And also explore this example file and others in that github since they are official. Most likely that third-party projects you’re using are outdated.

I mean I want to associate the Board with its User uid (author), so first I create a User, and then I use the user’s returned Uid as the author value in the boardForm. Which then cause the error in the title.


Btw, in the example you linked, the predicates also start with lower-case.

The lowercase thing was only a test I wanted to understand. Predicates are case sensitive. But building objects or JSON may be different. That’s what I wanted to find out. As I’m not a Go developer I do not know what the standards are.

I noticed something strange in your Schema. board: uid @reverse. Are you using this predicate where? seems to me a mistake there.

I think I’m probably doing it wrong, but not sure how to make the schema/mutation that can link to another uid, and I can’t find any examples about it… The alternative would be to link to a unique username string and then query for that, but that doesn’t seem efficient, and the next step would be to link posts to a board as well, so need to figure out how to link to a uid in any case…

There is some talk about it here but they only show Go code related to queries and not related to the schema and mutations

For me it seems ok the way you’re doing, it’s something wrong in your code in Go.

I made a visual example of what I understand about what you’re doing.

I modified little. But now you can use these queries.

{ 
 Users(func: has(_User) {
  uid
  expand(_all_) { 
      expand(_all_)  
      }
   }
}
{ 
 Users(func: has(_Board) {
  uid
  Title
  ~Author {
   uid
   Username
 }
  Description
  
}
}

In my example I added one more predicate to the Node “Board”. But you can use the same predicate for both example Nodes:

Node user you have the predicate “Boards” it will be a list. You will use it as Boards: uid @reverse . -
In this case, you are using a reverse logic. You would have to create the Board first, pick up this UID from this new Board and then create a new mutation from User to Board. Example

{
   "uid": "0x123", # Existing user
   "Boards": {
     "uid": "0x456" # New Board
   }
}

How you’re using reverse gets into this logic. This would be easier if you were using RDF. But I’m going to look at a better way for you to do this. But as I wrote it above, two predicates would be an ideal temporary solution.

in this second case (using reverse) you query would look like:

{ 
 Users(func: has(_Board) {
  uid
  Title
  ~Boards : Author {
   uid
   Username
 }
  Description
  
}
}

In RDF it would be much simpler, it would be so

	_:newBoard <_Board> " " .
	_:newBoard <Title> "My Title" .
	_:newBoard <Description> "My Description" .
	  <0x4> <Author> _:newBoard  # so it's reversed action herer

In JSON

{
   "_User": " ", # type as user
   "Username": "John88",
}

{
   "_Board": " ", # type as Board
    "Title": "My Title",
   "Description": "My Description"
}

And

{
   "uid": "0x123", # Existing user
   "Boards": {
     "uid": "0x456" # New Board
   }
}

Thanks, that diagram looks to be exactly what I’m trying to do.

This is my mutate func (that’s causing the error):

func DgraphMutateSetJson(data interface{}) (*api.Assigned, error) {
	mut := &api.Mutation{CommitNow: true}
	plainJSON, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	mut.SetJson = plainJSON
	return dgraphDB.NewTxn().Mutate(context.Background(), mut)
}

where dgraphDB = dgo.NewDgraphClient(api.NewDgraphClient(conn))

Maybe that’s the problem? That I’m simply trying to mutate the JSON as:

{"Title":"MyTitle","Description":"My Description","Author":"0x4"}

Maybe Author needs to be expressed in some other way?

as here

{
   "_Board": " ", # type as Board
   "Title": "My Title",
   "Description": "My Description"
   "Author": {
     "uid": "0x4" # Existing user
   }
}

*updated

Note A common mistake is to attempt to use {“uid”:“0x123”,“link”:“0x456”}. This will result in an error. Dgraph interprets this JSON object as setting the link predicate to the string"0x456", which is usually not intended.

Wow this works, thanks a lot… really appreciate it =)

1 Like

Hi Michel, I was wondering about one thing… if I only know user id (e.g 0x1), how can I quickly query all boards created by that user?

It seems it’s no problem to get the user uid and username if I know the board uid, but I’m not sure how to go the other way and get all boards belonging to that user…

There are several ways to do this, I will exemplify a simple one. But you could do the same using “uid_in” for example.

in this query i’m using multiple query blocks and the first one is a Var block.

more about Var block https://docs.dgraph.io/query-language/#var-blocks

you could also use graphql variables with below query
more about graphql variables https://docs.dgraph.io/query-language/#graphql-variables

{ 

var(func: uid(0x1)) {
  userBoards as Boards {
            uid
          }
     }
}
 theUserBoards(func: uid(userBoards) ) {
   Title
   Author
   Description
   }
}

In the var block you can induce multiple rules to find nodes you need. Can be used as a “pre-filter”.

Thanks for the quick reply. When I try to run the command it says

Your query did not return any results

But when I try to run:

{
  exists(func: uid(0xa)) {
    uid,
    title,
    description,
    user {
      uid,
      username,
    }
  }
}

It returns:

{
  "data": {
    "exists": [
      {
        "uid": "0xa",
        "title": "My board",
        "description": "My Description",
        "user": [
          {
            "uid": "0x1",
            "username": "My Username"
          }
        ]
      }
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 63064,
      "processing_ns": 669373,
      "encoding_ns": 2528204
    },
    "txn": {
      "start_ts": 154,
      "lin_read": {
        "ids": {
          "1": 50
        }
      }
    }
  }
}

I ran the command like this:

{
  var(func: uid(0x1)) {
    userBoards as board {
      uid
    }
  }
  theUserBoards(func: uid(userBoards) ) {
    uid
    title
    description
  }
}

because in my schema I changed to use lowercase, and I called it board: uid @count . instead of Boards.

Well, I set an example. You need to transform this example according to your context. Your build of nodes is different from mine. You’d have to share your entire context so I could give you an exact query.

When I created the user I only provided username: {"username":"My Username"}, and when I created board I provided title, description and user uid ({"title":"My board","description":"My Description","user":{"uid":"0x01"}})

And this is the current schema:

board: uid @count .
comment: uid @count .
thread: uid @reverse .
title: string @index(term, fulltext) .
description: string .
user: uid @reverse .
username: string @index(exact) .
creationTime: datetime .

Not sure if that gives enough info… I guess it makes sense that the var block query gives no results because it has no way of knowing that the board is associated with the user?