AWS AppSync Schema - Arrays of Connections Both Directions - amazon-web-services

My issue is that I need to have a connection between two schema models where each links to an array of the other. The scenario here is I have multiple Location, each Location has multiple Staff. Each Staff can also have multiple Location that they are authorized at.
I don't see a way to do this in the documentation. Originally I have each Location with multiple Staff, but this limits each Staff to 1 Location. I'm toying with the idea of altLocationNames as an array of strings with each Staff, but this would require me to perform an extra query of all Staff or all Locations if the altLocationNames is needed.
Does anybody know a clever way to do this, or even just the best way for me to get all Staff at Location as well as all Locations for a specific Staff?
Schemas:
type Staff
#model
#auth(rules: [{ allow: private, provider: iam }, { allow: private, provider: userPools }])
#key(fields: ["email"])
#key(name: "byId", fields: ["id"], queryField: "listStaffsById")
#key(name: "byLocation", fields: ["locationName", "recordedAt"], queryField: "listStaffsByLocation")
#key(name: "byRole", fields: ["role", "recordedAt"], queryField: "listStaffsByRole")
#key(name: "byStatus", fields: ["status", "recordedAt"], queryField: "listStaffsByStatus") {
email: AWSEmail!
altEmails: [AWSEmail]
id: ID!
locationName: String!
location: Location #connection(fields: ["locationName"])
altLocationNames: [String]
firstName: String
lastName: String
role: StaffRole
status: StaffStatus
recordedAt: AWSDateTime!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type Location
#model
#auth(rules: [{ allow: private, provider: iam }, { allow: private, provider: userPools }])
#key(fields: ["name"]) {
name: String!
subdomain: String
address: String
phone: String
email: AWSEmail
staff: [Staff] #connection(keyName: "byLocation", fields: ["name"])
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}

Can you create middle table between location and staff table and fetch via that table.
Example:
type Staff
#model {
id: ID!
name: String
locations: [StaffLocation] #connection(keyName: "staffLocationByStaffId", fields: ["id"])
}
type Location
#model {
id: ID!
name: String
staffs: [StaffLocation] #connection(keyName: "staffLocationByLocationId", fields: ["id"])
}
type StaffLocation
#key(name: "staffLocationByStaffId", fields: ["staffId"])
#key(name: "staffLocationByLocationId", fields: ["locationId"])
#model {
id: ID!
staffId: ID!
locationId: ID!
staff: Staff #connection(fields: ["staffId"])
location: Location #connection(fields: ["locationId"])
}

Related

AWS Amplify #belongsTo with #auth causes failure

I am currently experiencing an issue with #belongsTo in connection with #auth when more than one sortKey is inside of the parent element.
The following error comes up when I try to amplify push the schema:
🛑 Invalid #belongsTo on Comments:todo. Provided fields do not match the size of primary key(s) for Todos
Below schema should reproduce the error:
type Todos #model #auth(rules: [{ allow: public }]) {
id: ID!
createdAt: String
number: Int
title: String
description: String
comments: [Comments] #hasMany(indexName: "byComments", fields: ["id"])
baseType: String
#index(
name: "byNumber"
queryField: "todosByNumber"
sortKeyFields: ["number"]
)
#index(
name: "byTitle"
queryField: "todosByTitle"
sortKeyFields: ["title"]
)
#index(
name: "byDescription"
queryField: "todosByDescription"
sortKeyFields: ["description"]
)
}
type Comments #model #auth(rules: [{ allow: public }]) {
id: ID!
todosID: ID! #index(name: "byComments")
todo: Todos #belongsTo(fields: ["todosID"])
createdAt: String
firstName: String
lastName: String
messageID: ID #index(name: "commentsByMessages")
message: Messages #belongsTo(fields: "messageID")
}
type Messages #model #auth(rules: [{ allow: public }]) {
id: ID!
title: String
content: String
comments: [Comments] #hasMany(indexName: "byComments", fields: ["id"])
}
Does anyone have a solution on how to setup #belongsTo and #auth correctly?
Looking forward to your help!

AWS Amplify app sync error in content page of aws amplify

HI i am sharing my schema please provide suggestion. Whenever i open content page i got this error like sync error occured in this model.
type Message #model #auth(rules: [{allow: public}]) {
id: ID!
content: String!
userID: ID! #index(name: "byUser")
chatroomID: ID
}
type ChatRoom #model #auth(rules: [{allow: public}]) {
id: ID!
newMessages: Int
LastMessage: Message #hasOne
Messages: Message #hasOne
ChatRoomUsers: [User] #manyToMany(relationName: "ChatRoomUser")
}
type User #model #auth(rules: [{allow: public}]) {
id: ID!
name: String!
status: String
imageUri: String
Messages: [Message] #hasMany(indexName: "byUser", fields: ["id"])
chatrooms: [ChatRoom] #manyToMany(relationName: "ChatRoomUser")
}

How to create a many to many relationship in amplify datastore using schema.graphql

type StudentCourses
#model(queries: null)
#auth(rules: [{ allow: public }])
#key(name: "byStudent", fields: ["studentID", "courseID"])
#key(name: "byCourse", fields: ["courseID", "studentID"]) {
id: ID!
studentID: ID!
courseID: ID!
student: Student! #connection(fields: ["studentID"])
course: Course! #connection(fields: ["courseID"])
}
type Course
#model
#auth(rules: [{ allow: public }])
#key(name: "bySchool", fields: ["schoolID"]) {
id: ID!
courseName: String!
schoolID: ID!
students: [Student!] #connection(keyName: "byCourse", fields: ["id"])
}
type Student
#model
#auth(rules: [{ allow: public }])
#key(name: "bySchool", fields: ["schoolID"]) {
id: ID!
studentName: String
studentEmail: String
sisID: Int
schoolID: ID!
courses: [Course!] #connection(keyName: "byStudent", fields: ["id"])
}
I followed the steps in docs to create a many to many relationship between student and courses but i keep getting this error Key byCourse does not exist for model Student even thought i created a model to connect school and courses. Thanks in advance
You need to omit keyName from Course, since in Student model, you have list of courses, so you can't really have #key directive for that.
https://docs.amplify.aws/cli-legacy/graphql-transformer/connection/#many-to-many-connections
type Course
#model
#auth(rules: [{ allow: public }])
#key(name: "bySchool", fields: ["schoolID"]) {
id: ID!
courseName: String!
schoolID: ID!
students: [Student!] #connection(fields: ["id"])
}
Anyone who is upto V2 of Amplify, they can get guidance from this link
https://docs.amplify.aws/cli/graphql/data-modeling/#belongs-to-relationship
Updated Flow has the following changes
You need to add #manyToMany on both tables that are going to join
This will create a third table by itself and will add Queries and Mutations for it as well.

How to add filterInput field in amplify?

I got below schema (schema.graphql),
type Admin #model #auth(rules: [{ allow:owner }]) {
id: ID!
name: String!
}
type Staff #model #auth(rules: [{ allow:owner }]) {
id: ID!
name: String!
admin: Admin #connection
}
Now I want to fetch Staffs, filtering out by admin's ID.
But when I ran
API.graphql(
graphqlOperation(queries.listStaffs,
{
filter: {
admin: {
eq: adminId
}
}
}
))
It throws an error below.
The variables input contains a field name 'admin' that is not defined for input object type 'ModelStaffFilterInput'
Since there's no filter input field for admin. In the AppSync console,
input ModelStaffFilterInput {
id: ModelIDInput
name: ModelStringInput
and: [ModelStaffFilterInput]
or: [ModelStaffFilterInput]
not: ModelStaffFilterInput
}
In this case, how do you add filter input field to the GraphQL schema?
Would you supply any example of amplify/backend/api/pjname/shema.graphql ?
OK, I got this work.
All I had to do was explicitly put the key for the relation.
type Admin #model #auth(rules: [{ allow:owner }]) {
id: ID!
name: String!
}
type Staff #model #auth(rules: [{ allow:owner }]) {
id: ID!
name: String!
admin: Admin! #connection
staffAdminId: ID! # this field is needed, for generating filterInput
}
Then amplify push, which generated schema with staffAdminId:
input ModelStaffFilterInput {
staffAdminId: ModelIDInput
id: ModelIDInput
name: ModelStringInput
and: [ModelStaffFilterInput]
or: [ModelStaffFilterInput]
not: ModelStaffFilterInput
}
And run query like
listStaffs(filter: {staffAdminId: {eq: "adminID"}})
And this staffAdminId is already in the table, so it doesn't affect other than the graphql schema.
I got this from:
https://github.com/aws-amplify/amplify-cli/issues/300#issuecomment-475786380

AWS Amplify API error - field is not of type Int

I'm trying to push my AWS Amplify API schema/create the resource but it errors out saying:
✖ An error occurred when pushing the resources to the cloud
managerId field is not of type Int
The error goes away if I change managerId to an Int on the Writer type but I don't want to do that. It should be an ID. Any idea what's wrong here?
schema.graphql
type Writer implements Person
#model
#searchable
#key(name: "byManager", fields: ["managerId", "hourlyPay"])
#auth(rules: [
{allow: groups, groups: ["Admin"]},
{allow: public, provider: iam, operations: [read]}
])
{
id: ID!
managerId: ID!
name: String!
hourlyPay: Float!
manager: Manager! #connection(fields: ["managerId"])
}
type Manager implements Person
#model
#searchable
#auth(rules: [
{allow: groups, groups: ["Admin"]},
{allow: public, provider: iam, operations: [read]}
])
{
id: ID!
name: String!
department: String
writers: [Writer!]! #connection(keyName: "byManager", fields: ["id"])
}
Thanks!
I had the same issue in an Android project I was working on.
I fixed it by placing the next code in a file I created under app/src/main/graphql (I had to create the folder graphql).
/app/src/main/graphql/aws-directives.graphql
directive #connection(name: String, keyField: String, sortField: String, limit: Int) on FIELD_DEFINITION
Then, instead of using #key I only used the directive #connection like this
type Comment #model {
id: ID!
text: String!
postId: Post #connection(name: "commentsByPost")
}
type Post #model {
id: ID!
comments: [Comment] #connection(name: "commentsByPost")
}
Finally when you create comments you have to pass the postId. If you do a query to list the Posts and its comments you will get the comments associated with each post correctly.