在 AWS Amplify GraphQL DynamoDB 中按另一个表的字段(也称为交叉表或嵌套过滤)过滤列表查询
Posted
技术标签:
【中文标题】在 AWS Amplify GraphQL DynamoDB 中按另一个表的字段(也称为交叉表或嵌套过滤)过滤列表查询【英文标题】:Filtering List Query By Another Table's Field (a.k.a Cross-Table or Nested Filtering) in AWS Amplify GraphQL DynamoDB 【发布时间】:2021-08-02 17:29:23 【问题描述】:您的问题与哪个类别有关? DynamoDB、AppSync(GraphQL)
放大 CLI 版本 4.50.2
提供其他详细信息,例如代码sn-ps
背景: 我是 AWS 无服务器应用程序系统的新手,作为前端开发人员,我非常喜欢它,这要归功于自动生成的 API、表、连接、解析器等。我在前端和 S3、DynamoDB、AppSync 中使用 Angular/Ionic , Cognito, Amplify-cli 用于后端。
我有什么: 这是我的架构的一部分。我可以轻松地使用自动生成的 API 来列出/获取带有附加过滤器的反馈(即 score: ge: 3 )。感谢@connection,我可以在列出的反馈项中看到用户的详细信息。
type User @model @auth(rules: [ allow: owner ])
id: ID!
email: String!
name: String!
region: String!
sector: String!
companyType: String!
type Feedback @model @auth(rules: [ allow: owner ])
id: ID!
user: User @connection
score: Int!
content: String
我想要什么: 我想根据用户类型的几个字段列出反馈,例如用户的区域(即 user.region: contains: 'United States' )。现在我搜索了一个很像 #2311 的解决方案,我了解到 amplify codegen 只创建***过滤。为了使用跨表过滤,我相信我需要修改解析器、lambda 函数、查询和输入。其中,对于初学者来说,它看起来相当复杂。
我尝试过/考虑过的事情:
-
我尝试单独列出所有用户和反馈并在前端过滤它们。但随后客户端下载了所有这些不必要的数据。此外,由于分页限制,用户体验会受到影响,因为他们看到一个空列表并且需要反复点击“加载更多”按钮。
感谢一些建议,我还考虑在反馈表中复制用户详细信息以便能够搜索/过滤它们。那么问题是如果用户更新他/她的信息,重复的值将是过时的。另外会有太多重复的数据,因为我也需要这个功能来处理其他表。
我也听说过使用 ElasticSearch 来解决这个问题,但有人提到一个简单的过滤,他每月需要 30 美元的费用,所以我退缩了。
我尝试使用解析器解决方案在其中添加自定义过滤。但我发现这对于初学者来说相当复杂。此外,我还需要在许多其他表中进行这种跨表过滤,所以我认为这很难管理。如果这是最佳做法,如果有人能指导我完成它,我将不胜感激。
问题:
-
对我来说,实现这种跨表过滤的最简单/对初学者友好的解决方案是什么?我愿意接受替代解决方案。
对于无 SQL 设置,这种交叉表过滤是一种不好的方法吗?因为我需要两个表之间的一些关系。 (我认为@connection 就足够了)。我应该在为时已晚之前切换到 SQL 设置吗?
Amplify 将来是否可以为此自动生成解决方案?我觉得很多人都遇到了同样的问题。
提前谢谢你。
【问题讨论】:
【参考方案1】:Amplify 和真正的 DynamoDB 通常要求您提前考虑您的访问模式。有很多非常好的信息可以帮助指导您了解这个思维过程的样子。特别喜欢纳德·达比特的https://dev.to/dabit3/data-modeling-in-depth-with-graphql-aws-amplify-17-data-access-patterns-4meh
乍一看,我想我会在 User 模型中添加一个名为 byCountry 的新 @key,它会在 DDB 中为您在该属性上创建一个新的全局二级索引,并且还会为您提供一些新的查询方法。查看https://docs.amplify.aws/cli/graphql-transformer/key#designing-data-models-using-key 了解更多示例。
一旦您设置了 User.getByCountry,您就应该能够恢复每个用户的反馈。
query USAUsersWithFeedbacks
listUsersByCountry(country: "USA")
items
feedbacks
items
content
nextToken
nextToken
最后,您可以在 nextToken 不为 null 的情况下使用 javascript 获取所有内容。您将能够针对您感兴趣的每个国家/地区重复使用此功能,并且您应该能够通过添加额外的@keys 将此示例扩展到其他属性。
【讨论】:
感谢您提供的优质资源,我会继续调查。到目前为止,我在 User 模型中收集的 @key of byCountry 将允许按国家/地区查询用户。但我想按用户(发送反馈)国家/地区列出所有反馈。这有没有可能?如果你能给我一个小例子,我将不胜感激。 我用一个例子和更多解释编辑了原始答案。 这是我尝试过的:将 byRegion 键添加到用户模型。在用户模型中添加了带有 @connection 的反馈。在调用 CreateFeedback 时添加了 userFeedbacksId 参数。添加了自定义查询:UserByRegionWithFeedback。现在我可以按地区过滤用户,并在项目对象下接收反馈。现在,每次 nextToken 不为空时,我都可以重新调用此 api 以获取该区域中的所有用户。反馈如何?我看到它返回一个嵌套的 nextToken 但是,有没有办法使用这个 api 向该用户询问更多反馈?例如,如果用户超过 10 个,我不想错过任何一个。【参考方案2】:好的,感谢@alex 的回答,我实现了以下内容。我们的想法不是列出反馈并尝试按用户字段过滤它们,而是列出用户并从响应中收集他们的反馈:
更新 schema.graphql 如下:
type User
@model
@auth(rules: [ allow: owner ])
@key(name: "byRegion", fields: ["region"], queryField: "userByRegion") # <-- added byRegion key
id: ID!
email: String!
name: String!
region: String!
sector: String!
companyType: String!
feedbacks: [Feedback] @connection # <-- added feedbacks connection
在调用 CreateFeedback 时添加了 userFeedbacksId 参数。所以他们会在列出用户时出现。
在 src/graphql/custom-queries.graphl 下添加自定义查询 UserByRegionWithFeedback 并使用 amplify codegen 构建它:
query UserByRegionWithFeedback(
$region: String
$sortDirection: ModelSortDirection
$filter: ModelUserFilterInput
$limit: Int
$nextToken: String # <-- nextToken for getting more Users
$nextTokenFeedback: String # <-- nextToken for getting more Feedbacks
)
userByRegion(
region: $region
sortDirection: $sortDirection
filter: $filter
limit: $limit
nextToken: $nextToken
)
items
id
email
name
region
sector
companyType
feedbacks(nextToken: $nextTokenFeedback)
items
content
createdAt
id
score
nextToken
createdAt
updatedAt
owner
nextToken
现在我像下面这样调用这个 API:
nextToken =
user: null,
feedback: null
;
feedbacks: any;
async listFeedbacks()
try
const res = await this.api.UserByRegionWithFeedback(
'Turkey', // <-- region: filter Users by their region, I will add UI input later
null, // <-- sortDirection
null, // <-- filter
null, // <-- limit
this.nextToken.feedback == null ? this.nextToken.user : null, // <-- User nextToken: Only send if Feedback NextToken is null
this.nextToken.feedback // <-- Feedback nextToken
);
// Get User NextToken
this.nextToken.user = res.nextToken;
// Initialize Feedback NextToken as null
this.nextToken.feedback = null;
// Loop Users in the response
res.items.map((user) =>
// Get Feedback NextToken from User if it is not null (Or else last User in the list could overrite it)
if (user.feedbacks.nextToken)
this.nextToken.feedback = user.feedbacks.nextToken;
// Push the feedback items into the list to diplay in UI
this.feedbacks.push(...user.feedbacks.items);
);
catch (error)
this.handleError.show(error);
最后,我在 UI 中添加了一个加载更多按钮,该按钮调用 listFeedbacks() 函数。因此,如果有任何反馈 NextToken,我会将其发送到 API。 (请注意,多个用户反馈可以有一个 nextToken)。 如果所有反馈都正常并且有用户 NextToken,我将其发送到 API 并为新用户重复该过程。
我相信使用 SQL 设置可能会更简单,但目前还可以。我希望它可以帮助其他人在我的情况。如果有任何想法可以让它变得更好,我会全力以赴。
【讨论】:
【参考方案3】:我之前的回答在特定情况下仍然对其他人有用,但是当我意识到您可以在自定义查询中过滤嵌套项时,我找到了实现嵌套过滤的更好方法。
架构:
type User @model
id: ID!
email: String!
name: String!
region: String!
sector: String!
companyType: String!
feedbacks: [Feedback] @connection # <-- User has many feedbacks
自定义查询:
query ListUserWithFeedback(
$filter: ModelUserFilterInput # <-- Filter Users by Region or any other User field
$limit: Int
$nextToken: String
$filterFeedback: ModelFeedbackFilterInput # <-- Filter inner Feedbacks by Feedback fields
$nextTokenFeedback: String
)
listUsers(filter: $filter, limit: $limit, nextToken: $nextToken)
items
id
email
name
region
sector
companyType
feedbacks(filter: $filterFeedback, nextToken: $nextTokenFeedback)
items
content
createdAt
id
score
nextToken
createdAt
updatedAt
nextToken
$filter 可以是这样的:
region: contains: 'Turkey'
$filterFeedback 可以是:
and: [ content: contains: 'hello' , score: ge: 4 ]
这样可以同时过滤用户和反馈。
【讨论】:
以上是关于在 AWS Amplify GraphQL DynamoDB 中按另一个表的字段(也称为交叉表或嵌套过滤)过滤列表查询的主要内容,如果未能解决你的问题,请参考以下文章
aws amplify appsync 中的 Graphql 突变错误
AWS Amplify GraphQL Schema 导致错误
AWS Amplify (GraphQL) - 使用“graphqlOperation”与普通查询?
带有 AWS Amplify 的 GraphQL - 如何启用对查询的排序