-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataStore ignoring foreign key Id in @hasMany - @belongsTo relationships so authorizations and subscriptions don't work #11124
Comments
For this schema type Post @model {
id: ID!
title: String!
comments: [Comment] @hasMany
}
type Comment @model {
id: ID!
post: Post @belongsTo
content: String!
} You can filter comments by the post instance. For example: const post = await DataStore.query(Post, 'YOUR_POST_ID');
const comments = await DataStore.query(Comment, c => c.post.eq(post)); If you want to be able to specify the foreign key specifically, try type Post @model {
id: ID!
title: String!
comments: [Comment] @hasMany(indexName: "byPost", fields: ["id"])
}
type Comment @model {
id: ID!
postID: ID! @index(name: "byPost")
post: Post @belongsTo(fields: ["postID"])
content: String!
} Note: the const comments = await DataStore.query(Comment, c => c.postID.eq('YOUR_POST_ID')); Regarding your authorization question a couple points:
const post = await DataStore.save(new Post({ title: "test" }));
await DataStore.save(
new Comment({
post: post,
content: "test comment",
})
); The |
Thanks @iartemiev also for formating my question. Sorry if maybe I was not clear enough. I have already tried all the possible forms to cretate the field with the foreign key, including the one you mentioned that I also mentioned as the last way (the AppSync way) of creating it. With or without the "indexName" or "fields" attributes in the @hasmany declaration, the "fields" attribute in the @belongsTo declaration, or the "sortKeyFields" attribute in the @Index declaration, it doesn't matter, it does not work anyway. Please check it because this failure has been around for a long time. It is as simple as that the javascript models generated do not contain the foreign key field, I don't know if it is the same for Android or IOs libraries but in javascript it works that way and that is wrong because subscriptions filtering by this relation are not possible and I think it is really important and a key concept. And about the authorization sorry again if I was not clear enough. Yes, I use the pre token generator lambda trigger but that is not the problem. Probably it works with creation since you send the post Id, but in mutations it does not work. If instead of creating a Comment you just edit the "content" field of the Comment and then save it to DataStore, you will see that the field with the post Id is not sent in the request and, what is really important, it does not appear in the requested return fields and since subscriptions are based on this fields, this value is never compared with the values in the custom claim, therefore never sending the corresponding notifications to subscribers to changes on Comments for a Post Id or allowed to read them. Please let me know if there is something not clear yet. As I said, this has been around for quite long time and is as simple as include this field in the javascript models (created automatically or manually with the "fields" attribute in the @belongsTo declaration) and I think it is really important for regular use of DataStore and Amplify. |
I have discovered that even the input for the subscriptions to changes on this model Comment generated by the trasnformer does include this foreign key field to subscribe to changes on Comments that belong to a Post Id: input ModelSubscriptionCommentFilterInput {
postId: ModelSubscriptionIDInput
and: [ModelSubscriptionCommentFilterInput]
or: [ModelSubscriptionCommentFilterInput]
} So this is clearly an error in the Datastore model generation for javascript that should include this foreign key field. Please fix it as soon as possible so we can continue with the development. As a temporary workaround I have included a new field with an index in this model Comment to include this foreign key with the Id of the Post: type Comment @model {
id: ID!
post: Post @belongsTo
postIdWA: ID! @index(name: "byPostWA")
content: String!
} This is not ideal because everytime I create a Comment from the DataStore javascript code I have to fill both fields, the post and the postIdWA and check in the backend resolver that both Ids are the same, but at least now it allows me to subscribe to Comments filtering for this field: DataStore.configure({
syncExpressions: [
syncExpression(Comment, c => c.postIdWA.eq('YOUR_POST_ID'))
]
}); But what is surprising now (I don't know if this is the normal behavior) is that the ModelSubscriptionCommentFilterInput mentioned before does not include this field so, even if now the subscriptions are working, I am receiving warnings in the javascript console and in the socket messages to this subscriptions: Connection failed: {"errors":[{"message":"The variables input contains a field that is not defined for input object type 'ModelSubscriptionCommentFilterInput' "}]} If someone could explain me if this is normal and the way to get rid of those messages I would also apreciate it. |
any news about this? |
Hello. Any news about this? Should we abandon Amplify for real projects till it become stable? |
Hello. Any news about this? |
Hello. Any news about this? |
Before opening, please confirm:
JavaScript Framework
Angular
Amplify APIs
Authentication, GraphQL API
Amplify Categories
auth, api
Environment information
Describe the bug
When creating two models with a one to many relationship acording to the example on the documentation https://docs.amplify.aws/lib/datastore/relational/q/platform/js/:
It creates under the hood an attribute in the Comment model called postCommentsId where it stores the Id referencing to the Post it belongs to. It even creates a GSI with that field as primary key to make even easier to search for this attribute. This attribute can be used for instance from the query editor in the aws console for appsync, to query, sync or subscribe for Comments that belong to a Post with a particular post Id.
This is the ideal behaviour I think it should had. But the problem comes when I try to use this attribute with DataStore query or subscribe since it is not pressent on the javascript implementation that Amplify creates when generating models. In the documentation it says that you can query for the comments of a post by querying for the post and getting the comments field or directly querying for the comments with a post with that id:
But there is no option for querying directly for the Comments with a postCommentsId equal to the Post Id you want, even if this GSI actually exists. This is annoying with queries although it can be saved using the options in the documentation, but it becomes a big problem with subscriptions and authorizations. DataStore javascript classes do not allow to subscribe to fields in relationships:
This doesn't work and as the field postCommentsId does not exists in the javascript classes created, we can also not filter for that field so filter and only syncronize Comments that belong to a Post in a system with thousands of Comments becomes impossible.
It also create problems with authoization, if I use a custom claim to store the list of Posts a User has and I want to allow access to the Comments only to users that has the postCommentsId field among this Posts from the claim it doesn't work since mutations do not return this field among the attributes so the Auth resolver fails to "unauthorized".
I have tried by creating the field manually with the model:
Also creating the index like appsync says in the documentation here https://docs.amplify.aws/cli/graphql/data-modeling/#belongs-to-relationship:
But none of this works. This is a continuation of the issue #8285 that was closed and forgotten almost two years ago but I think this is very necessary.
Expected behavior
Datastore includes the foreign key Id attributes in one to many relationships in javascript generated classes so queries and subscriptions can use it.
Reproduction steps
Follow example in documentation.
Code Snippet
// Put your code below this line.
Log output
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
The text was updated successfully, but these errors were encountered: