Can i get amplify datastore to return related items in a query? - aws-amplify

I'm trying to get the related/child items with a datastore query. I have no problems getting them with the graphql API, but it returns a bunch of deleted items which i am unable to filter server side (and keep pagination working nicely).
I'm using react/next/javascript.
``
I have the following models in my schema:
type TestResultData #model #auth(rules: [{allow: public}, {allow: owner, operations: [create, read, update]}, {allow: groups, groups: ["admin"], operations: [read, create, update, delete]}]) {
id: ID!
name: String
value: String
unit: String
testresultsID: ID! #index(name: "byTestResults")
TestResultAnalyses: [TestResultAnalysis] #hasMany(indexName: "byTestResultData", fields: ["id"])
tests: [Test] #manyToMany(relationName: "TestTestResultData")
}
and
type TestResults #model #auth(rules: [{allow: public}, {allow: owner, operations: [create, read, update]}, {allow: groups, groups: ["admin"], operations: [read, create, update, delete]}]) {
id: ID!
CustomerID: ID! #index(name: "byCustomer")
lab: String
fasting: Boolean
dateReported: AWSDateTime
dateCollected: AWSDateTime
dateTested: AWSDateTime
type: [TestType]
note: String
UploadedFiles: [UploadedFiles] #hasMany(indexName: "byTestResults", fields: ["id"])
TestResultData: [TestResultData] #hasMany(indexName: "byTestResults", fields: ["id"])
}
and I would like to query my TestResults model and have it return the nested TestResultData. However, datastore does not seem to return the related items. (if i do the query using the graphql api it works perfectly, except it contains all my deleted items, which i cannot filter)
this command gets me the TestResults without child items
const data = await DataStore.query(TestResults);
I've also tried "querying relations" as per:
https://docs.amplify.aws/lib/datastore/relational/q/platform/js/#updated-schema
but it doesn't work. I've also upgraded to the latest version of amplify.

Related

AppSync error: Not Authorized to access listTodos on type Query

I've set up a basic app to test Amplify's #auth rules. I have this simple graphql.schema:
type Todo #model #auth(rules: [{ allow: public }]) {
id: ID!
name: String!
description: String
}
type Blog #model #auth(rules: [{ allow: owner }]) {
id: ID!
name: String!
posts: [Post] #hasMany
}
...
When I try to perform a simple list operation with AppSync, Blog succeeds, but Todo returns an error: Not Authorized to access listTodos on type Query
I have set my API (amplify update api) to use Cognito User Pools as the default auth, and to use API key as a secondary auth type. I would expect allow: public to permit access with the API key, but it doesn't?

AWS FlutterAmplify using DataStore

How can we get the User Conversations with a query. Ideal would be to do a query to the user table and get all the user conversations loaded.
example:
final user = await Amplify.DataStore.query(User.classType, where: User.ID.eq(id))
user.conversations to have the list of conversations loadd.
If that can not be done, next would be to get all the conversations that have a specific User.
example not working:
await Amplify.DataStore.query(UserConversation.classType
where: UserConversation.USER.eq(user.id)
)
type Message #model #auth(rules: [{allow: public}]) {
id: ID!
ConversationId: Conversation #connection
UserId: User #connection
body: String
createdDate: AWSDateTime!
}
type Conversation #model #auth(rules: [{allow: public}]) {
id: ID!
date: AWSDateTime
readBy: [ReadBy] #connection(keyName: "byConversation", fields: ["id"])
users: [UserConversation] #connection(keyName: "byConversation", fields: ["id"])
name: String
image: String
}
type ReadBy #model #auth(rules: [{allow: public}]) #key(name: "byConversation", fields: ["conversationID"]) {
id: ID!
date: AWSDateTime
RedByUsers: User #connection
conversationID: ID
}
type User #model #auth(rules: [{allow: public}]) {
id: ID!
firstName: String
lastName: String
userImg: String
createdDate: AWSDateTime
updatedDate: AWSDateTime
email: AWSEmail
conversations: [UserConversation] #connection(keyName: "byUser", fields: ["id"])
}
type UserConversation #model(queries: null) #key(name: "byUser", fields: ["userID", "conversationID"]) #key(name: "byConversation", fields: ["conversationID", "userID"]) #auth(rules: [{allow: public}, {allow: public}]) {
id: ID!
userID: ID!
conversationID: ID!
user: User! #connection(fields: ["userID"])
conversation: Conversation! #connection(fields: ["conversationID"])
}
I was able to get the second version by doing the following:
await Amplify.DataStore.query(UserConversation.classType
where: User.ID.eq(user.id)
);
The above will perform a selection of all user conversations that have the user id equal to whatever the id of the user variable is. It was a bit confusing at first as to why you need to pass the User.ID for the query, but from what I understand it is due to how the SQL query gets created by AWS DataStore, it is doing a join behind the scenes and therefore will use the column of the second table (in this case the User table) to perform the join. I wish I could point to some documentation on this, but I couldn't find any. I kinda just got lucky trying a bunch of stuff and noticing in the error message how the SQL query is generated.

Amplify JS API GraphQL Elasticsearch throws "ResolverExecutionLimitReached" error

I've implemented the Amplify JS Library with a Vue project and have had success with all of the features of the library except this issue. When I query a model with Elasticsearch, it returns the appropriate results, but also the error of "ResolverExecutionLimitReached".
This is the request:
let destinations = await API.graphql(graphqlOperation(queries.searchDestinations, {filter: { deviceId: { eq: params.id }}}))
This is the schema:
type Destination
#model
#searchable
#auth(rules: [{ allow: public }, { allow: private }])
#key(name: "byXpoint", fields: ["xpoint"])
#key(name: "byDevice", fields: ["deviceId"])
{
id: ID!
index: Int!
levels: [String]
name: String!
xpoint: String
sourceId: ID
Source: Source #connection
lock: Boolean
breakaway: Boolean
breakaways: String
probeId: ID!
probe: Probe #connection(fields: ["probeId"])
deviceId: ID!
device: Device #connection(fields: ["deviceId"])
orgId: ID!
org: Org #connection(fields: ["orgId"])
}
And this returns:
{
data: {
searchDestinations: {items: Array(100), nextToken: "ba1dc119-2266-4567-9b83-f7eee4961e63", total: 384}
},
errors: [
{
data: null
errorInfo: null
errorType: "ResolverExecutionLimitReached"
locations: []
message: "Resolver invocation limit reached."
path: []
}
]
}
My understanding is the AppSync API has a hard limit of returning more than 1000 entries, but this query is on a table with only ~600 entries and is only returning 384. I am executing the same command via AppSync directly via a NodeJS application and it works without issue.
Not sure where to investigate further to determine what is triggering this error. Any help or direction is greatly appreciated.
Connections in the schema were causing the single request to go beyond the 1000 request limit (exactly as stated by Mickers in the comments). Updated schema with less connections on fetch and issue was resolved.

Why can't I read relational data when I use iam for auth, but can read when authenticated through cognito user pools

My project uses cognito user pools as the default authentication method and also uses iam for my custom graphql lambda resolver.
I've been using the AppSync console to run tests on my queries/mutations.
I have a many-to-many relationship between User and Group types which I've implemented in this schema.graphql file.
type User
#model
#auth(
rules: [
{ allow: owner, ownerField: "id", operations: [create, update, delete] }
{ allow: private, provider: iam, operations: [read, update, delete] }
{ allow: private, provider: userPools, operations: [read] }
]
) {
id: ID!
displayName: String!
groups: [GroupMemberLink] #connection(keyName: "byMember", fields: ["id"])
}
type Group
#model
#auth(
rules: [
{ allow: owner, ownerField: "members", operations: [create, update, delete] }
{ allow: private, provider: iam, operations: [read, update, delete] }
{ allow: private, provider: userPools, operations: [read] }
]
) {
id: ID!
name: String!
members: [String]!
associated: [GroupMemberLink] #connection(keyName: "byGroup", fields: ["id"])
}
type GroupMemberLink
#model(queries: null, subscriptions: null)
#key(name: "byGroup", fields: ["groupID", "memberID"])
#key(name: "byMember", fields: ["memberID", "groupID"])
#auth(
rules: [
{ allow: private, provider: userPools, operations: [read] }
# what am I doing wrong below?
{ allow: private, provider: iam, operations: [create, read, update, delete] }
]
) {
id: ID!
groupID: ID!
memberID: ID!
group: Group! #connection(fields: ["groupID"])
member: User! #connection(fields: ["memberID"])
}
My Intentions:
To only allow my lambda function (using iam) to both read and do mutations (create/update/delete)
To allow users authenticated with cognito user pools to only read.
My Problem:
My lambda function is not able to read this relational type/field when I query either from the User or Group type. It also seems like users are able to create this type of object which is something I absolutely do not want.
What am I doing wrong? I understand that multi-auth was recently added so this might be tricky.
Reading the documentation hasn't helped me much so I've been trying many different combinations of rules and hoping one would work.
Update: I get this error whenever I try to access the connected field on either the User or Group type: Not Authorized to access items on type ModelGroupMemberLinkConnection" from the appsync console using iam as the auth type.
To clarify: users authenticated with cognito user pools have both read/write access (Shouldn't have write access), but my lambda function using iam doesn't have read or write access.
Things I've tried that still result in not being to access the related field while being authenticated with iam:
Remove the auth directive altogether.
Changed the auth rule in GroupMemberLink to #auth(rules: [{ allow: private, provider: iam, operations: [read, update, delete] }])
Update:
These are the queries I've been testing in the AppSync console:
query GetUser {
getUser(id: "funksouldev") {
id
displayName
groups {
items {
group {
id
name
}
}
}
}
}
query GetGroup($groupID: ID!) {
getGroup(id: $groupID) {
id
associated {
items {
id
member {
id
displayName
}
}
}
}
}
Okay, Finally I think this would solve the problem.
type ModelGroupMemberLinkConnection #aws_iam
#aws_cognito_user_pools
{
items: [GroupMemberLink]
nextToken: String
}

AppSync GraphQL query with nested objects

I'm starting a new project using AWS Amplify, and have some trouble to correctly define my schema for my use case with nested objects
I have the following schema
type Company
#model
{
id: ID!
name: String!
teams: [Team] #connection (name: "CompanyTeams", sortField: "name")
}
type Team
#model
{
id: ID!
name: String!
users: [User] #connection (name: "TeamUsers", sortField: "createdAt")
company: Building #connection (name: "CompanyTeams", sortField: "name")
teamCompanyId: ID!
}
type User
#model
{
id: ID!
createdAt: String
name: String!
email: String!
team: Unit #connection (name: "TeamUsers")
}
I would like to be able to query a list of teams based on a list of companies and a user name.
For example, get all teams in companies A/B/C with user name starts with "David".
Is my current schema fine for that?
I can easily retrieve a list of teams based on the company with this kind of query
query listTeams {
listTeams(filter: {
teamCompanyId: {
eq:"A"
}
}) {
items {
name
}
}
}
But not sure how to include search on the user model. Should I override the filter and add a new custom resolver including the new filters?
Also is using filters the best solution? I believe with DynamoDB filter is only applied after we got results from the query or scan. And due to the limitation of 1mb, it might introduce a lot of reads to retrieve some results?
Happy to get any insights as I'm relatively new with AppSync / GraphQL and DynamoDB.
Thanks.

Resources