Querying entities with contained entities

I have a question which is probably a general GraphQL issue, not necessarily a dgraph issue, but thought maybe someone would be kind to lend a hand.

Take this schema

type Player {
    name: String! @id
    attributes: [PossessedAttribute] @hasInverse(field:player)
}

type Attribute {
    name: String! @id
}

type PossessedAttribute {
    id: ID!
    player: Player!
    attribute: Attribute!
    level: Int!
}

For argument’s sake, assume that the Attribute entity is indeed “entity-worthy”. In other words I simply can’t use its name identity as is—I need to reference it in the PossessedAttribute class.

Here’s the mutation to add two Players:

mutation {
  addAttribute(
    input: [{ name: "strength" }, { name: "dexterity" }, { name: "empathy" }]
  ) {
    attribute {
      name
    }
  }
  addPlayer(
    input: [
      {
        name: "John"
        attributes: [
          {
            attribute: { name: "strength" }
            level: 5
          },          
          {
            attribute: { name: "dexterity" }
            level: 10
          }
        ]
      },
      {
        name: "Karen"
        attributes: [
          {
            attribute: { name: "strength" }
            level: 6
          },          
          {
            attribute: { name: "empathy" }
            level: 9
          }
        ]
      }
    ]
  ) {
    player {
      name
      attributes {
        attribute {
          name
        }
      }
    }
  }
}

Now, searching for Players that have a PossessedAttribute is where I’m fumbling.

query {
  queryPlayer {
    name
    attributes {
      attribute(filter: {name: {eq: "dexterity"}}) {
        name
      }
    }
  }
}

Yields this:

{
  "errors": [
    {
      "message": "Non-nullable field 'attribute' (type Attribute!) was not present in result from Dgraph.  GraphQL error propagation triggered.",
      "locations": [
        {
          "line": 5,
          "column": 7
        }
      ],
      "path": [
        "queryPlayer",
        0,
        "attributes",
        0,
        "attribute"
      ]
    },
    {
      "message": "Non-nullable field 'attribute' (type Attribute!) was not present in result from Dgraph.  GraphQL error propagation triggered.",
      "locations": [
        {
          "line": 5,
          "column": 7
        }
      ],
      "path": [
        "queryPlayer",
        1,
        "attributes",
        0,
        "attribute"
      ]
    },
    {
      "message": "Non-nullable field 'attribute' (type Attribute!) was not present in result from Dgraph.  GraphQL error propagation triggered.",
      "locations": [
        {
          "line": 5,
          "column": 7
        }
      ],
      "path": [
        "queryPlayer",
        1,
        "attributes",
        1,
        "attribute"
      ]
    }
  ],
  "data": {
    "queryPlayer": [
      {
        "name": "John",
        "attributes": [
          null,
          {
            "attribute": {
              "name": "dexterity"
            }
          }
        ]
      },
      {
        "name": "Karen",
        "attributes": [
          null,
          null
        ]
      }
    ]
  }
}

The results are there, but as you can see it’s not that elegant. I realize this just might be a bad schema for the query requirement, or maybe there’s some GraphQL magic that I’ve yet to discover.

Any help appreciated, I’ll definitely buy you a beer at the next Dgraph conference!

Use cascade, this works !! Because you have applied filter after printing names , so the players which don’t have attribute “dexterity” also gets printed. And for them attribute name results null, and it gives error while printing because attribute field is non null in graphql schema. Cascade returns the results which matches all the filters/conditions in query and reject partial matches.

query {
  queryPlayer@cascade {
    name
    attributes {
      attribute(filter: {name: {eq: "dexterity"}}) {
        name
      }
    }
  }
}
{
  "data": {
    "queryPlayer": [
      {
        "name": "John",
        "attributes": [
          {
            "attribute": {
              "name": "dexterity"
            }
          }
        ]
      }
    ]
  },
  "extensions": {
    "touched_uids": 19
  }
}
1 Like

Thanks Jatin. Looks like a solution indeed. However, I get

{
  "errors": [
    {
      "message": "Unknown directive \"cascade\".",
      "locations": [
        {
          "line": 2,
          "column": 15
        }
      ]
    }
  ]
}

Using Altair…

Which version of Dgraph are you using?
@cascade is available only in master at the moment, it is not released yet. Will be out in v20.07.0-beta and the releases after that.

OK, that explains it. I’m running v20.03.1.

Thanks!