I Want to Do
I’d like to figure out how to handle/design N to 1 relationship in Dgraph
What I Did
I have the following two types of entities defined in the schema
type Object {
xid
name
namespace
resource
links
}
type Resource {
xid
name
group
version
kind
namespaced
}
xid: string @index(exact) .
name: string @index(exact) .
namespace: string @index(exact) .
links: [uid] @count @reverse .
created_at : datetime @index(hour) .
group: string @index(exact) .
version: string @index(exact) .
kind: string @index(exact) .
namespaced: bool .
resource: uid .
Now, there can be several Object
s pointing to the same Resource
. By reading this comment I’ve learned that Dgraph does not support unique UIDs across types, which make me wonder about some questions:
- Say I create 2
Object
s which share the sameResource
i.e. theResource
should be globally unique. I can guarantee the uniqueness on my side viaxid
field in the schema definition, but that still would not prevent Dgraph from creating newResource
nodes which leads to unnecessary data bloat and a bit tricky handling of R<->O relationship in terms of consistency i…e say I update aResource
with some XID (which I guarantee will be unique) – I now have to update all instances ofResource
which have the samexid
to make sure the update is consistent across allObject
s that share the sameResource
. I understand I can create a “map” type i.e. intermediary node but that would not solve the problem with large updates.
Is there any way to somehow deal with this situation in, say, more “performant” less redundant way or this is simply not possible?
- Say I want to link two entities, but I don’t know what Dgraph Types they are. All I know is their
XID
s (i.e. externallly managed unique IDs). Here I figured I can link to SAME Types of entities like this
query := `
{
from as var(func: eq(xid, "` + from.Value() + `")) {
fid as uid
}
to as var(func: eq(xid, "` + to.Value() + `")) {
tid as uid
}
}
`
weight := 1.0
relation := "Test"
node := &Object{
UID: "uid(fid)",
DType: []string{"Object"},
Links: []Object{
{UID: "uid(tid)", DType: []string{"Object"}, Relation: relation, Weight: weight},
},
}
pb, err := json.Marshal(node)
if err != nil {
return fmt.Errorf("link json marshal: %w", err)
}
mu := &dgapi.Mutation{
Cond: `@if(gt(len(from), 0) AND gt(len(to), 0))`,
SetJson: pb,
}
req := &dgapi.Request{
Query: query,
Mutations: []*dgapi.Mutation{mu},
CommitNow: true,
}
if _, err := s.c.NewTxn().Do(ctx, req); err != nil {
return fmt.Errorf("txn Link: %w", err)
}
I wonder how do I do that when I want to link Object
and Resource
if all I know are their XID
s. There are 3 possible combinations
O -> R
O -> O
R -> O
I suspect I could retrieve DType
in a query like so:
query := `
{
from as var(func: eq(xid, "` + from.Value() + `")) {
fid as uid
}
to as var(func: eq(xid, "` + to.Value() + `")) {
tid as uid
}
}
fromUid(func: uid(fid)) {
uid
xid
dgraph.type
}
`
And then maybe based on the returned type I’d hack up Go
code so the linking is correct as per the relationship type. This however feels a bit clunky and it seems to me I wouldn’t be able to do Upstert
easily from Go
code in this situation given the way Object
s are linked (many to many) and how Object
is linked to Resource
(many to 1) i.e. for O<->
link something like this works:
node := &Object{
UID: "uid(fid)",
DType: []string{"Object"},
Links: []Object{
{UID: "uid(tid)", DType: []string{"Object"}, Relation: relation, Weight: weight},
},
}
However, for O->R
I’d need something like this:
node := &Object{
UID: "uid(fid)",
DType: []string{"Object"},
Resource: Resource{UID: "uid(tid)", DType: []string{"Resource"}}
}
The problem is you can’t do “both” in an upsert. You’d need to query, get the results back, parse them, create the right mutation
object (either of the above) based on the returned dgraph.type
and do the mutation.
It seems to me that if the UID
s across Type
s were unique the linking between Resource
and Object
entities would be a piece of cake.
That being said, I’m quite new to Graph databases so I might be missing something fundamental here.
Dgraph Metadata
dgraph version
$ dgraph version
[Decoder]: Using assembly version of decoder
Page Size: 4096
Dgraph version : v20.11.0
Dgraph codename : tchalla
Dgraph SHA-256 : 8acb886b24556691d7d74929817a4ac7d9db76bb8b77de00f44650931a16b6ac
Commit SHA-1 : c4245ad55
Commit timestamp : 2020-12-16 15:55:40 +0530
Branch : HEAD
Go version : go1.15.5
jemalloc enabled : true
For Dgraph official documentation, visit https://dgraph.io/docs/.
For discussions about Dgraph , visit http://discuss.dgraph.io.
Licensed variously under the Apache Public License 2.0 and Dgraph Community License.
Copyright 2015-2020 Dgraph Labs, Inc.