v20.03.1 and master
yes
linux (not relevant)
Load GraphQL schema:
interface Record {
id: ID!
}
type Parent implements Record {
name: String
children: [Child]
}
type Child implements Record {
label: String! @search(by: [hash])
}
Add records:
mutation AddParent {
addParent (input:[name:"First parent",children:[
{label:"Child 1"},
{label:"Child 2"},
{label:"Child 3"}
]}]) {
numUids
}
}
Remove one child record by id:
mutation RemoveChild {
deleteChild (filter:{id:["0x3"]}) {
msg
numUids
}
}
List all parent records with children:
query ListParents {
queryParent
{
name
id
children {
id
label
}
}
}
Expected result:
{
"data": {
"queryParent": [
{
"name": "First parent",
"id": "0x4",
"children": [
{
"id": "0x2",
"label": "Child 3"
},
{
"id": "0x5",
"label": "Child 2"
}
]
}
]
}
}
Actual result:
{
"errors": [
{
"message": "Non-nullable field 'label' (type String!) was not present in result from Dgraph. GraphQL error propagation triggered.",
"locations": [
{
"line": 8,
"column": 7
}
],
"path": [
"queryParent",
0,
"children",
1,
"label"
]
}
],
"data": {
"queryParent": [
{
"name": "First parent",
"id": "0x4",
"children": [
{
"id": "0x2",
"label": "Child 3"
},
null,
{
"id": "0x5",
"label": "Child 2"
}
]
}
]
}
}
I think the null record (and the error message) should not be returned.
Hi @miko
This is expected behaviour. When you delete a node, the incoming edges to it are not deleted, only the outgoing edges are. Since the child doesn't have any outgoing edges to the Parent, they are not deleted. Also, the node itself remains, so there still remains a node with id 0x3 and the parent node would still point to it.

Hence, when you do the query you get the error because label field has been deleted for the node with id 0x3. If you ran the query, without asking for the label, no error would be returned.
query ListParents {
queryParent
{
name
id
children {
id
}
}
}
If you want the cleanup of the parent => child edge to happen automatically, you'll have to modify the schema to have the @hasInverse directive i.e.
interface Record {
id: ID!
}
type Parent implements Record {
name: String
children: [Child] @hasInverse(field: parent)
}
type Child implements Record {
label: String! @search(by: [hash])
parent: [Parent]
}
in this case your Graph would look like the diagram below

so when you delete a child node, we would follow along to all the outgoing edges and delete the inward edges coming from them. In your case, we would delete the link from parent 0x4 to child 0x3. I am closing this issue but feel free to reopen if you have anymore questions.
Great explanation. Can it be added to the documentation?
Most helpful comment
Hi @miko
This is expected behaviour. When you delete a node, the incoming edges to it are not deleted, only the outgoing edges are. Since the child doesn't have any outgoing edges to the Parent, they are not deleted. Also, the node itself remains, so there still remains a node with id
0x3and the parent node would still point to it.Hence, when you do the query you get the error because
labelfield has been deleted for the node with id0x3. If you ran the query, without asking for the label, no error would be returned.If you want the cleanup of the parent => child edge to happen automatically, you'll have to modify the schema to have the
@hasInversedirective i.e.in this case your Graph would look like the diagram below

so when you delete a child node, we would follow along to all the outgoing edges and delete the inward edges coming from them. In your case, we would delete the link from parent
0x4to child0x3. I am closing this issue but feel free to reopen if you have anymore questions.