Amplify-cli: using @connection and @key

Created on 13 Oct 2020  路  4Comments  路  Source: aws-amplify/amplify-cli

Which Category is your question related to?
Using GraphQL directives to create complex relationships

This is my GraphQL Schema

type Person @model {
  id: ID!
  colleague: [Person!]
  memberOf: [Organization!]
}

type Organization @model {
  id: ID!
  department: [Organization!]
  member: [Person!]
  subOrganization: [Organization!]
}

What is the recommended way to model these relationships using the @model and @key directives?

After reading the docs, it seems like I have to create a join model but I'm wondering if there's another way.

Thanks for your help!

@connection @key question

Most helpful comment

@alexboulay Yes, you will have to create a join model when the connection is M:N. The schema could potentially look like this

type Person @model {
  id: ID!
  colleague: [ColleagueConnection]
    @connection(keyName: "byPerson", fields: ["id"])
  memberOf: [OrganizationEmployee]
    @connection(keyName: "byPerson", fields: ["id"])
}

type Organization @model {
  id: ID!
  department: [OrganizationDepartment!]
    @connection(keyName: "byDepartment", fields: ["id"])
  member: [Person!]
  subOrganization: [OrganizationSubOrganization]
    @connection(keyName: "byDepartment", fields: ["id"])
}

type ColleagueConnection
  @model(queries: null)
  @key(name: "byPerson", fields: ["personId"]) {
  personId: ID!
  colleagueId: ID!
  colleague: Person @connection(fields: ["colleagueId"])
}

type OrganizationEmployee
  @model(queries: null)
  @key(name: "byPerson", fields: ["personId"]) {
  personId: ID!
  person: Person @connection(fields: ["personId"])
  organizationId: ID!
  organization: Organization @connection(fields: ["organizationId"])
}

type OrganizationDepartment
  @model(queries: null)
  @key(name: "byDepartment", fields: ["departmentId"]) {
  departmentId: ID!
  organizationId: ID!
  organization: Organization @connection(fields: ["organizationId"])
}

type OrganizationSubOrganization
  @model(queries: null)
  @key(name: "byDepartment", fields: ["departmentId"]) {
  departmentId: ID!
  subOrganizationId: ID!
  subOrganization: Organization @connection(fields: ["subOrganizationId"])
}

All 4 comments

@alexboulay Yes, you will have to create a join model when the connection is M:N. The schema could potentially look like this

type Person @model {
  id: ID!
  colleague: [ColleagueConnection]
    @connection(keyName: "byPerson", fields: ["id"])
  memberOf: [OrganizationEmployee]
    @connection(keyName: "byPerson", fields: ["id"])
}

type Organization @model {
  id: ID!
  department: [OrganizationDepartment!]
    @connection(keyName: "byDepartment", fields: ["id"])
  member: [Person!]
  subOrganization: [OrganizationSubOrganization]
    @connection(keyName: "byDepartment", fields: ["id"])
}

type ColleagueConnection
  @model(queries: null)
  @key(name: "byPerson", fields: ["personId"]) {
  personId: ID!
  colleagueId: ID!
  colleague: Person @connection(fields: ["colleagueId"])
}

type OrganizationEmployee
  @model(queries: null)
  @key(name: "byPerson", fields: ["personId"]) {
  personId: ID!
  person: Person @connection(fields: ["personId"])
  organizationId: ID!
  organization: Organization @connection(fields: ["organizationId"])
}

type OrganizationDepartment
  @model(queries: null)
  @key(name: "byDepartment", fields: ["departmentId"]) {
  departmentId: ID!
  organizationId: ID!
  organization: Organization @connection(fields: ["organizationId"])
}

type OrganizationSubOrganization
  @model(queries: null)
  @key(name: "byDepartment", fields: ["departmentId"]) {
  departmentId: ID!
  subOrganizationId: ID!
  subOrganization: Organization @connection(fields: ["subOrganizationId"])
}

Feel free to comment here if you need clarifications

Thanks for your help @yuth! I was able to follow your examples easily. However, I am now facing some limitations and I would love your input.

I have this schema:

type Person @model @searchable{
   id: ID!
   knowsAbout: [PersonDefinedTerm!] @connection(keyName: "byPerson", fields: ["id"])
}

type DefinedTerm  @model {
    id: ID!
    termCode: String!
    name: String
    description: String
    image: String
}

type PersonDefinedTerm
  @model(queries: null)
  @key(name: "byPerson", fields: ["personId"]) {
  definedTermId: ID!
  personId: ID!
  definedTerm: DefinedTerm @connection(fields: ["definedTermId"])
}

What I would like to do is be able to use listPersons and/or searchPersons and filter by the one or more DefinedTerm. However, it seems that the filter option doesn't support nested objects, only primitives. I have multiple other nested objects within Person that I want to filter my queries by. How can I achieve this natively? Am I forced to create custom resolvers? If so, I wonder what kind of sensible approach can I take.

Or is there something wrong with my understanding or current approach?

Thank you!

What I ended up doing is adding a list of IDs and keywords to Person that refer to the DefinedTerm. That way, I can have faceted and keyword search. The challenge is synchronizing those list with the join table. It works, but it would be great to have a more robust solution.

Was this page helpful?
0 / 5 - 0 ratings