Consider the following schema
interface Sortable {
id: ID!
sortings: [Sorting!]!
}
type Sorting {
id: ID!
sequence: Int!
contextRef: String! @search(by: [exact])
}
type Course {
id: ID!
title: String!
chapters: [Chapter!]
}
type Chapter implements Sortable {
id: ID!
title: String!
# from Sortable
# sortings: [Sorting!]!
}
So one Course
can have multiple Chapters
which again have multiple Sortings
. I have multiple sortings because I want to allow that one chapter can also belong to many courses but with a different sorting. Here’s a sketch to visualise the data model:
Hence the contextRef
basically tells me in which context (in this case type Course
) one specific sorting is valid. I should mention that the context reference not necessarily needs to be the parent node!
I have contextRef
of type String
because I need the ability to filter sortings according to the scope I’m dealing with.
query Course($id: ID!, $string_id: String!) {
queryCourse(filter: { id: $id }) {
id
title
chapters {
id
title
sortings(filter: { contextRef: { eq: $string_id } }) {
sequence
}
}
}
}
Note that $id
and $string_id
are the same values - specifically the course UID
.
So far so good. This will work but I have problems with assigning contextRef
properly in a single upsert
block.
1. Assiging a UID as a string
If I create a new chapter inside a course, I would run this DQL upsert mutation. I have to run the query since the parent node of Chapter
is not necessarily the reference node! Thus, I cannot rely on getting the correct reference UID submitted in my custom resolver.
{
"query": "{ qCourse(func: uid(<ID>)) { c as uid } }",
"set": {
"uid": "uid(c)",
"Course.chapters": {
"dgraph.type": ["Chapter", "Sortable"],
"Chapter.title": "Chapter Z",
"Sorting.sequence": 0,
"Sorting.contextRef": "uid(c)"
}
}
}
Unfortunately extracting “uid(c)” for a field of type string is prohibited and thus this is not an option.
Is there a way to assign a
UID
to a value variable which can be extracted withval()
?
2. Filtering by an edge UID
The other approach would be having a proper edge to the node which serves as reference. Thus, I’d extend the schema like so
interface Node {
id: ID!
}
interface Sortable {
id: ID!
sortings: [Sorting!]!
}
type Sorting {
id: ID!
sequence: Int!
contextRef: Node!
}
type Course implements Node {
id: ID!
title: String!
chapters: [Chapter!]
}
type Chapter implements Sortable {
id: ID!
title: String!
# from Sortable
# sortings: [Sorting!]!
}
Now I can easily assign the reference node to the new chapter by
{
"query": "{ qCourse(func: uid(<ID>)) { c as uid } }",
"set": {
"uid": "uid(c)",
"Course.chapters": {
"dgraph.type": ["Chapter", "Sortable"],
"Chapter.title": "Chapter Z",
"Sortable.sortings": {
"dgraph.type": "Sorting",
"Sorting.sequence": 0,
"Sorting.contextRef": "uid(c)"
}
}
}
}
The problem is that I have no clue if I could filter by an edge UID but I guess this is not possible.
query Course($id: ID!) {
queryCourse(filter: { id: $id }) {
id
title
chapters {
id
title
sortings(filter: { contextRef: {id: $id} }) {
sequence
}
}
}
}
Is there a way of filtering by an edge UID?
The only solution that I found so far, is having an additional @id
field for all nodes which are referenceable and either mapping the UID
to this field or introducing UUIDs
. The concept with UUIDs would allow a single DQL mutation on create, whereas the “mapping” of the UID would require to generate the node first and afterwards assign the UID (as string) in a separate mutation.
Any help appreciated!