How best to specify ownership of a node

I am coming from a background in MySQL database design. Trying to wrap my brain around these new graphing database concepts and trying to unlearn some of the things that RDBMSs have taught me over the years. I am still learning the differences between graphql, dql, graphql+-, etc, while at the same time learning the syntax for all the different systems invovled.

I am writing a test app in Go, using the dgraph-io/dgo library. The app is intended to help me understand how to create graph data that has various interconnected relationships between the nodes.

What I want to do

I want to enter “notes” into the database. I want the notes to belong to me (or whoever is entering a note).

Questions:

  • What is the best way to specify that the Note is owned by a specific user?
  • Is it better to have an owner(uid) predicate/property or an IsOwnedBy edge?

Am I thinking about this incorrectly? I am still used to thinking in tables, columns, rows, primary keys, key relation tables. Trying to now think in the Dgraph way.

What I did

Here is the schema I have come up with so far:

const schema string = `
	type User {
		user_name
	}

	type Note {
		owner
		title
		body
		created
		updated
	}

	user_name: string @index(term) .
	title: string @index(term) .
	body: string @index(fulltext) .
	owner: [uid] .
	created: datetime .
	updated: datetime .
`

Here are the related data structures in Go:

---
type User struct {
	Uid        string   `json:"uid,omitempty"`
	Name       string   `json:"name,omitempty"`
	Notes      []Note   `json:"notes,omitempty"`
	Friends    []User   `json:"friends,omitempty"`
	DgraphType []string `json:"dgraph.type,omitempty"`
}

type Note struct {
	Uid        string    `json:"uid,omitempty"`
	Owner      string    `json:"owner,omitempty"` // User.Uid ??
	Title      string    `json:"title,omitempty"`
	Body       string    `json:"body,omitempty"`
	Created    time.Time `json:"created,omitempty"`
	Updated    time.Time `json:"updated,omitempty"`
	DgraphType []string  `json:"dgraph.type,omitempty"` // []string{"Note"}
}

When I try to save a note in the database along with the uid of the owner I get the following error:

noteBytes, err := json.Marshal(incomingNote) // type Note
mutation := &api.Mutation{SetJson: noteBytes, CommitNow: true}
response, err := dgraphConnection.NewTxn().Mutate(context.TODO(), mutation)

error:
  rpc error:
    code = Unknown
    desc = Input for predicate "owner" of type uid is scalar.
           Edge: entity:40002 attr:"owner" value:"0x7532" value_type:STRING 

GraphQL and DQL are similar. Once you understand one, the other will be pretty easy to deal with. GraphQL+- is in fact DQL. It was renamed to avoid confusion with GraphQL itself.

Always edges.

Naming an edge is a good personal convention. I would go with IsOwnedBy it is more meaningful cuz it tells the direction of the relation (parent → child).

Some inconsistency here. Your schema says that the owner is UID type. But your code says it is a string. BTW, it is okay to have a loop of link. e.g User to Note and Note to User in different edges. But you have to give a purpose to it in your Graph Model. Otherwise, it is just redundant data. You could just simply use reverse edge instead.

2 Likes

Yes, this is a bit confusing for me. All the dgo documentation seems to have the UID defined in Go as string. I found this schema document that says the “UID Type” is a uint64 in Go. But then I noticed some other examples in dgo that were setting the edges with Go types. So I tried that:

// changed
Owner string
// to
Owner User // custom type
// then passed the uid as a field on the custom type
Owner:      User{Uid: "0x7532"}

It worked!

      {
        "uid": "0xc352",
        "title": "Note Title",
        "body": "Note body.",
        "created": "2021-03-17T23:11:47.759601-06:00",
        "updated": "2021-03-17T23:11:47.759601-06:00",
        "dgraph.type": [
          "Note"
        ],
        "owner": [
          {
            "uid": "0x7532"
          }
        ]
      }

Do I understand correctly that, in this example, owner is the directed edge (parent → child)? If so, then I think I will take your advice and rename it to IsOwnedBy.

Thank you for the help, @MichelDiz.

Yes. But you also have ~Notes []Note json:"notes,omitempty"~ which is also (parent → child || user → notes).

Not a big deal tho.

1 Like