Hello,
I want to build the following app but I'm really confusing about graphql and cognito users.
The structure will be the following:
Users signed up using cognito and then user can create an organisation.
An organisation has many users
Summary:
Users can have many organisations
Organisation can have many users.
the confusing part is how the graphql schema will be.
Any suggestions or articles about it?
Thanks!
Have you checked out: https://docs.amplify.aws/cli/graphql-transformer/connection#many-to-many-connections? You can implement many to many using two 1-M @connections, an @key, and a joining @model. It also provides an example.
Does the organization have other cognito users? The doc that @xitanggg referred to should have information about how to set up the models but let us know if you need anymore clarification1
@ammarkarachi yes the organisation will have other cognito users. Do you have any suggestions how implement this?
type User @model
@key(name: "byOrganization", fields: ["organizationID", ])
{
id: ID!
username: String!
organizations: [Organization] @connection(keyName: "byCreator", fields: ["id"])
}
type Organization @model
@key(name: "byCreator", fields: ["creatorId"])
{
id: ID!
creatorId: ID
...otherOrganizationAttributes
users: [User] @connection(keyName: "byOrganization", fields: ["id"])
}
This is something that I came up on the fly but this should get you started in the right direction
type User @model @key(name: "byOrganization", fields: ["organizationID", ]) { id: ID! username: String! organizations: [Organization] @connection(keyName: "byCreator", fields: ["id"]) } type Organization @model @key(name: "byCreator", fields: ["creatorId"]) { id: ID! creatorId: ID ...otherOrganizationAttributes users: [User] @connection(keyName: "byOrganization", fields: ["id"]) }This is something that I came up on the fly but this should get you started in the right direction
I am afraid this wouldn't work for many to many relationships without a joining model.
Say a user with id: user1 creates an organization with id: org1. It would be impossible to link another user id: user2 to id: org1.
The page I referred to earlier has a detailed example of many to many relationships between a Post and a User. Substituting Post with Organization and Edit with Member would give you the schema you need.
type Organization @model {
id: ID!
title: String!
members: [OrganizationMember] @connection(keyName: "byOrganization", fields: ["id"])
}
# Create a join model and disable queries as you don't need them
# and can query through Organization.members and User.organizations
type OrganizationMember
@model(queries: null)
@key(name: "byOrganization", fields: ["organizationID", "memberID"])
@key(name: "byMember", fields: ["memberID", "organizationID"]) {
id: ID!
organizationID: ID!
memberID: ID!
organization: Organization! @connection(fields: ["organizationID"])
member: User! @connection(fields: ["memberID"])
}
type User @model {
id: ID!
username: String!
organizations: [OrganizationMember] @connection(keyName: "byMember", fields: ["id"])
}
This way, a user with id: user1 is created separately from an organization with id: org1. user1 is added to org1 by creating a OrganizationMember that contains user1 and org1. And user2 can be added to org1 by creating a OrganizationMember that contains user2 and org1.
When you said that you want to create an app where Users signed up using cognito and then user can create an organisation., I hope you know that when users signed up, all their data is stored in Cognito. What you are creating with graphql stores data in DynamoDB by default. That being said, you have to manually create your user profile at DynamoDB on first sign up to proceed with the above schema. Hope this helps.
Thanks @xitanggg I tried your implementation and works well.. I don't know if is the best possible solution but works.. @ammarkarachi what's your opinion about this implementation?
Since the same user can only be in the same organization once, you might be able to optimize it a bit by replacing a global secondary index with a composite primary index for OrganizationMember.
type Organization @model {
id: ID!
title: String!
members: [OrganizationMember] @connection(fields: ["id"])
}
# Create a join model and disable queries as you don't need them
# and can query through Organization.members and User.organizations
type OrganizationMember
@model
@key(fields: ["organizationID", "memberID"])
@key(name: "byMember", fields: ["memberID", "organizationID"]) {
organizationID: ID!
memberID: ID!
organization: Organization! @connection(fields: ["organizationID"])
member: User! @connection(fields: ["memberID"])
}
type User @model {
id: ID!
username: String!
organizations: [OrganizationMember] @connection(keyName: "byMember", fields: ["id"])
}
or
type Organization @model {
id: ID!
title: String!
members: [OrganizationMember] @connection(keyName: "byOrganization", fields: ["id"])
}
# Create a join model and disable queries as you don't need them
# and can query through Organization.members and User.organizations
type OrganizationMember
@model
@key(fields: ["memberID", "organizationID"])
@key(name: "byOrganization", fields: ["organizationID", "memberID"]){
memberID: ID!
organizationID: ID!
organization: Organization! @connection(fields: ["organizationID"])
member: User! @connection(fields: ["memberID"])
}
type User @model {
id: ID!
username: String!
organizations: [OrganizationMember] @connection(fields: ["id"])
}
Haven't tested this, but something like either one of this should work.