Questions regarding deep mutation

Context

Screenshot 2020-10-05 at 6.58.14 PM

  • There are three entities, Respondent, Question, and Choice.
  • A respondent is a person responding to questions.
  • A respondent can be asked multiple questions.
  • A question can contain one or multiple choices.
  • A choice can belong to one or multiple questions.
  • A respondent can select none or multiple choices.
  • Unique identifiers: username for Respondent, qid for Question, and cid for Choice.

Schema:

type Question {
  qid: String! @id
  text: String
  choices: [Choice] @hasInverse(field: questions)
  respondents: [Respondent]
}
type Choice {
  cid: String! @id
  text: String
  questions: [Question]
  respondents: [Respondent]
}
type Respondent {
  username: String! @id
  questions: [Question] @hasInverse(field: respondents)
  choices: [Choice] @hasInverse(field: respondents)
}

First mutation

Starting fresh, inserting a respondent answering a question with certain choices.

mutation ($input: [AddRespondentInput!]!) {
  addRespondent(input: $input) {
    numUids
  }
}
{
	"input": [
		{
			"username": "arya",
			"questions": [
				{
					"qid": "qid1",
					"text": "What cars do you currently own?",
					"choices": [
						{
							"cid": "cid1",
							"text": "Toyota"
						}
					]
				}
			]
		}
	]
}

Query respondents

query {
  queryRespondent {
    username
    questions {
      qid
      text
      choices {
        cid
        text
      }
    }
    choices {
      cid
      text
      questions {
        qid
        text
      }
    }
  }
}
# result:
  {
    "queryRespondent": [
      {
        "username": "arya",
        "questions": [
          {
            "qid": "qid1",
            "text": "What cars do you currently own?",
            "choices": [
              {
                "cid": "cid1",
                "text": "Toyota"
              }
            ]
          }
        ],
        "choices": [] # choices are empty here
      }
    ]
  }

Second mutation

Add another respondent answering the same question but with different choices.

{
	"input": [
		{
			"username": "john",
			"questions": [
				{
					"qid": "qid1",
					"text": "What cars do you currently own?",
					"choices": [
						{
							"cid": "cid1",
							"text": "Toyota"
						},
						{
							"cid": "cid2",
							"text": "BMW"
						}
					]
				}
			]
		}
	]
}

Query respondents again

 {
    "queryRespondent": [
      {
        "username": "arya",
        "questions": [
          {
            "qid": "qid1",
            "text": "What cars do you currently own?",
            "choices": [
              {
                "cid": "cid1",
                "text": "Toyota"
              }
            ]
          }
        ],
        "choices": []
      },
      {
        "username": "john",
        "questions": [
          {
            "qid": "qid1",
            "text": "What cars do you currently own?",
            "choices": [
              {
                "cid": "cid1",
                "text": "Toyota"
              }
            ]
          }
        ],
        "choices": []
      }
    ]
  }

Questions

  1. In the first mutation, I expect choices to be linked to respondents, but it was not the case. What am I doing wrong here?
  2. In the second mutation, john chose Toyota and BMW, but BMW wasn’t added. Why is that?

Continue experimenting with the First Mutation.
If I change the input to alt-1, I’ll get an error couldn't rewrite mutation addRespondent because failed to rewrite mutation payload because duplicate XID found: qid1.

# alt-1
{
  "input": [
    {
      "username": "arya",
      "questions": [
        {
          "qid": "qid1",
          "text": "What cars do you currently own?",
          "choices": [
            {
              "cid": "cid1",
              "text": "Toyota"
            }
          ]
        }
      ],
      "choices": [
        {
          "cid": "cid1",
          "text": "Toyota",
          "questions": [
            {
              "qid": "qid1",
              "text": "What cars do you currently own?"
            }
          ]
        }
      ]
    }
  ]
}

If I change the input to alt-2, I’ll get the following result.

# alt-2
{
  "queryRespondent": [
    {
      "username": "arya",
      "questions": [
        {
          "qid": "qid1",
          "text": "What cars do you currently own?",
          "choices": []
        }
      ],
      "choices": [
        {
          "cid": "cid1",
          "text": "Toyota",
          "questions": []
        }
      ]
    }
  ]
}

This is not what I want as well because the linkage of Question and Choice is not there.

For comparison, I got what I want using DQL.

Mutation

{
  set {
    _:r <dgraph.type> "Respondent" .
    _:q <dgraph.type> "Question" .
    _:c <dgraph.type> "Choice" .
    
    _:r <Respondent.username> "arya" .
    _:r <Respondent.questions> _:q .
    _:r <Respondent.choices> _:c .
    
    _:q <Question.qid> "qid1" .
    _:q <Question.text> "What cars do you currently own?" .
    _:q <Question.respondents> _:r .
    _:q <Question.choices> _:c .
    
    _:c <Choice.cid> "cid1" .
    _:c <Choice.text> "Toyota" .
    _:c <Choice.questions> _:q .
    _:c <Choice.respondents> _:r .
  }
}

Query respondents

{
  "queryRespondent": [
    {
      "username": "arya",
      "questions": [
        {
          "qid": "qid1",
          "text": "What cars do you currently own?",
          "choices": [
            {
              "cid": "cid1",
              "text": "Toyota"
            }
          ]
        }
      ],
      "choices": [
        {
          "cid": "cid1",
          "text": "Toyota",
          "questions": [
            {
              "qid": "qid1",
              "text": "What cars do you currently own?"
            }
          ]
        }
      ]
    }
  ]
}

If you want to add Choices to the Respondent you should add them to its array:

{
	"input": [
		{
			"username": "john",
			"questions": [
				{
					"qid": "qid1",
					"text": "What cars do you currently own?",
				}
			]
                       "choices": [
				{
					"cid": "cid1",
					"text": "Toyota"
				},
				{
					"cid": "cid2",
					"text": "BMW"
				}
			]
		}
	]
}

It happened because your input is for qid1 which is already exist after the first input and because it is an id you cannot insert another input with a question that its id is qid1.
If you want to do that you have to update it first with cid2 and then you will get the appropriate result

So here is a query that should works as you expect

mutation newChoice {
  addChoice(input: [{cid: "cid1", text: "Toyota"}]) {
    cid
  }
}

mutation newRespondent {
  addRespondent(input: [{username: "Arya", questions: [{qid: "qid1", text: "What cars do you currently own?", choices: ["cid1"]}], choices: ["cid1"]}]) {
    username
  }
}

In GQL you have to create the object you’re referencing first and then add it to its parent.
You can skip this step only if you create the object directly under its parent and not just referencing it.
Here you want to reference cid1 in two places so you have to create it before.

1 Like

Just to make sure I understand this correctly.
GQL cannot have the creation of objects and referencing them multiple times in a single mutation. Right?