One to Many Relationship not showing in the object Amplify Schema definition

3.5k views Asked by At

I am new to using amplify with GraphQL. I was setting up my DB schema and auto-generating the functions after running amplify push.

Goals I want to achieve but do not know how to are

  1. I would like to be able to get user with all connected information (with one to one and one to many relationships) in the returned object from getUser
  2. I would like to still be able to get userByUserName and see all connected one-to-many relationships as well

When calling the API generated function to get the user,

let user = await API.graphql(graphqlOperation(getUser,{id:userId}))

I am getting a user object back, however, it looks like this - even though I am definitely sure that data is set up correctly in the database.

buttons: {nextToken: null} -- WANT THIS TO INCLUDE ACTUAL INFORMATION ABOUT BUTTONS CONNECTED TO THIS USER
createdAt: "2020-09-02T23:41:12.278Z"
customStyles: {id: "e3d1bbef-ec6f-4a6d-9b5d-e693e890d4e0", bgColor: "F9FF9F", bgBtnColor: "FFFFFF", bgBtnHoverColor: "000000", textColor: "000000", …}
defaultStyles: null
email: "[email protected]"
firstName: "Nata"
id: "d683a6bb-383e-4cf1-943a-05b3da4e5cc3"
lastName: "Vache"
socialNetwork: {nextToken: null} -- WANT THIS TO INCLUDE ACTUAL INFORMATION ABOUT SOCIAL NETWORKS CONNECTED TO THIS USER, THE SAME WAY AS FOR EXAMPLE customStyles IS SHOWN. 
updatedAt: "2020-09-02T23:41:12.278Z"
userName: "Nata568"

type User @model @key(name: "byUserName", fields: ["userName"], queryField: "userByUserName"){
  id: ID!
  firstName: String!
  lastName: String!
  userName: String!
  email: String!
  socialNetwork: [UserSocialNetwork] @connection(keyName: "UserSocialNetworkUser", fields: ["id"])
  buttons: [Button] @connection(keyName: "ButtonUser", fields: ["id"])
  defaultStyles: DefaultStyle @connection
  customStyles: CustomStyle @connection
}

type UserSocialNetwork @model @key(name: "UserSocialNetworkUser", fields: ["userID", "id"], queryField:"userSocialNetworkByUserID") {
  id: ID!
  socialNetworkUsername: String!
  userID: ID!
  supportedSocialNetwork: SupportedSocialNetwork! @connection
}

type SupportedSocialNetwork @model {
  id: ID!
  name: String!
  address: String!
}

type Button @model @key(name: "ButtonUser", fields: ["userID", "id"], queryField: "buttonByUserID") {
  id: ID!
  name: String!
  address: String!
  image: String
  userID: ID!
}

This schema does not include all my model definitions - customStyles, defaultStyles, and the rest but they are one to one relationship, which is working perfectly fine. I am having issues with one-to-many relationships, such as User to UserSocialNetwork and User to Buttons.

I have read lots of resources about this on AWS Amplify Docs, have gone through examples but still have not found anything that I could work with that would allow me to get the information from connections on getUser call and also give me the ability to get the user by username. Any input would be appreciated!!!

2

There are 2 answers

2
Zanndorin On

General comment: If username is unique you could use that as the id instead of creating the extra index. If it isn't there will be problems with this schema since it can't do a getOperation but instead will do a query which might return multiple answers.

(The resolver in Appsync wants to use a dynamoDB.get by default (& design) but using an index would be a dynamoDB.query which results in a lot issues)

Anyway using your schema I can get it to work just fine when using the id

  "data": {
    "getUser": {
      "createdAt": "2020-09-07T13:54:23.440Z",
      "email": "meax",
      "firstName": "Max",
      "id": "19a752ec-5050-4e02-8ff8-05d9523e7ea5",
      "socialNetwork": {
        "items": [
          {
            "socialNetworkUsername": "What",
            "id": "280ec8ea-5b25-46d3-8f22-f170e3210146",
            "userID": "19a752ec-5050-4e02-8ff8-05d9523e7ea5"
          }
        ]
      },
      "lastName": "Sc",
      "userName": "zanndo",
      "updatedAt": "2020-09-07T13:54:23.440Z",
      "buttons": {
        "items": [
          {
            "id": "65971568-b388-40a3-b99e-1bff0a730161",
            "image": null,
            "address": "ButonAdre"
          }
        ]
      }
    }
  }
}

This being my query

getUser(id: "19a752ec-5050-4e02-8ff8-05d9523e7ea5") {
    createdAt
    email
    firstName
    id
    socialNetwork {
      items {
        socialNetworkUsername
        id
        userID
      }
    }
    lastName
    userName
    updatedAt
    buttons {
      items {
        id
        image
        address
      }
    }
  }
}

Here is one where I made email the id.

query MyQuery {
  getUser(id: "[email protected]") {
    id
    firstName
    lastName
    socialNetwork {
      items {
        socialNetworkUsername
        supportedSocialNetwork {
          name
          id
          address
        }
      }
    }
    buttons {
      items {
        id
        address
        name
      }
    }
  }
}

Also works

{
  "data": {
    "getUser": {
      "id": "[email protected]",
      "firstName": "S",
      "lastName": "W",
      "socialNetwork": {
        "items": [
          {
            "socialNetworkUsername": "SomeUserNameOrSomething",
            "supportedSocialNetwork": {
              "name": "Supported1",
              "id": "daf52246-4b25-402c-9fdd-46f8f35e1b89",
              "address": "SupportedAddr"
            }
          }
        ]
      },
      "buttons": {
        "items": [
          {
            "id": "9883bd91-a2f1-479d-ab65-7a4bbe7b2dc4",
            "address": "ButtonAddr",
            "name": "Button1"
          }
        ]
      }
    }
  }
}

Bonus using your index

  userByUserName(userName: "SW") {
    items {
      buttons {
        items {
          name
          id
        }
      }
      socialNetwork {
        items {
          socialNetworkUsername
          supportedSocialNetwork {
            name
          }
        }
      }
    }
  }
"userByUserName": {
      "items": [
        {
          "buttons": {
            "items": [
              {
                "name": "Button1",
                "id": "9883bd91-a2f1-479d-ab65-7a4bbe7b2dc4"
              }
            ]
          },
          "socialNetwork": {
            "items": [
              {
                "socialNetworkUsername": "SomeUserNameOrSomething",
                "supportedSocialNetwork": {
                  "name": "Supported1"
                }
              }
            ]
          }
        }
      ]
    }

This was the schema I used

type User @model @key(name: "byUserName", fields: ["userName"], queryField: "userByUserName"){
  firstName: String!
  lastName: String!
  userName: String!
  id: String!
  socialNetwork: [UserSocialNetwork] @connection(keyName: "UserSocialNetworkUser", fields: ["id"])
  buttons: [Button] @connection(keyName: "ButtonUser", fields: ["id"])
}

type UserSocialNetwork @model @key(name: "UserSocialNetworkUser", fields: ["userID", "id"], queryField:"userSocialNetworkByUserID") {
  id: ID!
  socialNetworkUsername: String!
  userID: String!
  supportedSocialNetwork: SupportedSocialNetwork! @connection
}

type SupportedSocialNetwork @model {
  id: ID!
  name: String!
  address: String!
}

type Button @model @key(name: "ButtonUser", fields: ["userID", "id"], queryField: "buttonByUserID") {
  id: ID!
  name: String!
  address: String!
  image: String
  userID: String!
}

Maybe I have misunderstood something?

1
Arosha On

This is a problem with query Depth. It is 2 by default and need to increase it (to 4 in your case).

You can resolve this by following below steps. In your cmd in your project root, (where you normally run amplify commands).

  1. Run amplify codegen configure - This will prompt configs again.
  2. Enter 4 for this option Enter maximum statement depth [increase from default if your schema is deeply nested]
  3. Run amplify codegen - this will create your queries and mutations according to the new depth.

You can verify it by checking grapgql/queries.js.

Earlier you could see below fragment in getUser query in grapgql/queries.js,

buttons {
  nextToken
}

But after following above resolution steps, it should be something like below.

buttons {
    items {
        id
        image
        address
      }
  }

Finally query for your user again.