如何处理 aws-appsync 中的关系?
How to work with relationships in aws-appsync?
我是 aws 和 graphql 的新手。我正在研究 appsync 并尝试在两种类型之间建立关系。以下是我的架构:
type BadCustomer {
id: ID!
name: String!
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
type BadCustomerConnection {
items: [BadCustomer]
nextToken: String
}
input CreateBadCustomerInput {
name: String!
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
input CreateDamageInput {
damage: Float!
comment: String
}
input CreateIndustryInput {
name: String!
}
input CreateSubscriberInput {
name: String!
email: AWSEmail!
phone: AWSPhone
streetAddress: String!
subscriberIndustryId: ID!
}
type Damage {
id: ID!
customer: BadCustomer!
industry: Industry!
victim: Subscriber!
damage: Float!
comment: String
}
type DamageConnection {
items: [Damage]
nextToken: String
}
input DeleteBadCustomerInput {
id: ID!
}
input DeleteDamageInput {
id: ID!
}
input DeleteIndustryInput {
id: ID!
}
input DeleteSubscriberInput {
id: ID!
}
type Industry {
id: ID!
name: String!
subscribers(
filter: TableSubscriberFilterInput,
sortDirection: ModelSortDirection,
limit: Int,
nextToken: String
): SubscriberConnection
}
type IndustryConnection {
items: [Industry]
nextToken: String
}
enum ModelSortDirection {
ASC
DESC
}
type Mutation {
createIndustry(input: CreateIndustryInput!): Industry
updateIndustry(input: UpdateIndustryInput!): Industry
deleteIndustry(input: DeleteIndustryInput!): Industry
createSubscriber(input: CreateSubscriberInput!): Subscriber
updateSubscriber(input: UpdateSubscriberInput!): Subscriber
deleteSubscriber(input: DeleteSubscriberInput!): Subscriber
createBadCustomer(input: CreateBadCustomerInput!): BadCustomer
updateBadCustomer(input: UpdateBadCustomerInput!): BadCustomer
deleteBadCustomer(input: DeleteBadCustomerInput!): BadCustomer
createDamage(input: CreateDamageInput!): Damage
updateDamage(input: UpdateDamageInput!): Damage
deleteDamage(input: DeleteDamageInput!): Damage
}
type Query {
getIndustry(id: ID!): Industry
listIndustries(filter: TableIndustryFilterInput, limit: Int, nextToken: String): IndustryConnection
getSubscriber(id: ID!): Subscriber
listSubscribers(filter: TableSubscriberFilterInput, limit: Int, nextToken: String): SubscriberConnection
getBadCustomer(id: ID!): BadCustomer
listBadCustomers(filter: TableBadCustomerFilterInput, limit: Int, nextToken: String): BadCustomerConnection
getDamage(id: ID!): Damage
listDamages(filter: TableDamageFilterInput, limit: Int, nextToken: String): DamageConnection
}
type Subscriber {
id: ID!
name: String!
email: AWSEmail!
phone: AWSPhone
streetAddress: String!
industry: Industry!
}
type SubscriberConnection {
items: [Subscriber]
nextToken: String
}
type Subscription {
onCreateIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["createIndustry"])
onUpdateIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["updateIndustry"])
onDeleteIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["deleteIndustry"])
onCreateSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["createSubscriber"])
onUpdateSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["updateSubscriber"])
onDeleteSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["deleteSubscriber"])
onCreateBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["createBadCustomer"])
onUpdateBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["updateBadCustomer"])
onDeleteBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["deleteBadCustomer"])
onCreateDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["createDamage"])
onUpdateDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["updateDamage"])
onDeleteDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["deleteDamage"])
}
input TableBadCustomerFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
phone: TableStringFilterInput
email: TableStringFilterInput
streetAddress: TableStringFilterInput
dob: TableStringFilterInput
passportNumber: TableStringFilterInput
driversLicenceNumber: TableStringFilterInput
ipAddress: TableStringFilterInput
}
input TableBooleanFilterInput {
ne: Boolean
eq: Boolean
}
input TableDamageFilterInput {
id: TableIDFilterInput
damage: TableFloatFilterInput
comment: TableStringFilterInput
}
input TableEventFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
where: TableStringFilterInput
when: TableStringFilterInput
description: TableStringFilterInput
}
input TableFloatFilterInput {
ne: Float
eq: Float
le: Float
lt: Float
ge: Float
gt: Float
contains: Float
notContains: Float
between: [Float]
}
input TableIDFilterInput {
ne: ID
eq: ID
le: ID
lt: ID
ge: ID
gt: ID
contains: ID
notContains: ID
between: [ID]
beginsWith: ID
}
input TableIndustryFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
}
input TableIntFilterInput {
ne: Int
eq: Int
le: Int
lt: Int
ge: Int
gt: Int
contains: Int
notContains: Int
between: [Int]
}
input TableStringFilterInput {
ne: String
eq: String
le: String
lt: String
ge: String
gt: String
contains: String
notContains: String
between: [String]
beginsWith: String
}
input TableSubscriberFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
email: TableStringFilterInput
phone: TableStringFilterInput
streetAddress: TableStringFilterInput
}
input UpdateBadCustomerInput {
id: ID!
name: String
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
input UpdateDamageInput {
id: ID!
damage: Float
comment: String
}
input UpdateIndustryInput {
id: ID!
name: String
}
input UpdateSubscriberInput {
id: ID!
name: String
email: AWSEmail
phone: AWSPhone
streetAddress: String
subscriberIndustryId: ID
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
我想在 Subscribers
和 Industry
之间建立关系。每个订户属于一个行业。我为 Subscriber.industry
和 Industry.subscribers
设置了解析器。
Subscriber.industry
解析器,数据源Industry
table:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.subscriberIndustryId, "___xamznone____"))
}
}
Industry.subscribers
解析器,数据源Subscriber
table:
#set( $limit = $util.defaultIfNull($context.args.limit, 10) )
{
"version": "2017-02-28",
"operation": "Query",
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "id"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
},
"scanIndexForward": #if( $context.args.sortDirection )
#if( $context.args.sortDirection == "ASC" )
true
#else
false
#end
#else
true
#end,
"filter": #if( $context.args.filter )
$util.transform.toDynamoDBFilterExpression($ctx.args.filter)
#else
null
#end,
"limit": $limit,
"nextToken": #if( $context.args.nextToken )
"$context.args.nextToken"
#else
null
#end
}
我有以下疑问:
query ListIndustries {
listIndustries {
items {
id
name
subscribers {
items {
id
name
streetAddress
}
}
}
}
}
query ListSubscribers {
listSubscribers{
items {
id
name
industry {
name
}
}
}
}
如果我 运行 ListSubscribers
在 appsync 控制台上查询,它会给我想要的结果,例如:
{
"data": {
"listSubscribers": {
"items": [
{
"id": "d04d6ef4-95bf-4b01-9a6a-13f550dbfa8f",
"name": "John Doe",
"industry": {
"name": "Real Estate"
}
},
{
"id": "96fa3e60-fdcf-4a6d-a3b6-72ec2c4701d1",
"name": "Jane Doe",
"industry": {
"name": "Ecommerce"
}
},
{
"id": "413dd506-afd4-474e-a850-54a39eb1eeeb",
"name": "John Doe",
"industry": {
"name": "Real Estate"
}
}
]
}
}
}
但是如果我 运行 ListIndustries
查询,它不会给我该行业的订阅者列表,例如:
{
"data": {
"listIndustries": {
"items": [
{
"id": "b904d8f3-b504-48e0-b28f-0f9ac1742186",
"name": "Real Estate",
"subscribers": {
"items": []
}
},
{
"id": "167b87f2-3342-4390-80af-df53ba3c6f73",
"name": "Ecommerce",
"subscribers": {
"items": []
}
}
]
}
}
}
需要有人帮我解决这个问题。
我在 Industry.subscribers
解析器中错过了 index
。添加它解决了问题。
我需要更多信息才能确定,但看起来 Industry.subscribers 解析器可能配置错误。您的查询表达式当前指定:
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "id"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
}
// There is no "index" so this is trying to query the primary index.
也就是说,"Query the primary index where the 'id' = $ctx.source.id"。根据您粘贴的对象,看起来您的订阅者对象使用 $util.autoId()
,因此订阅者 'id' 永远不会等于行业 'id'。如果使用 Amplify CLI 的 @connection 指令,默认情况下将在订阅者 table 上创建一个 GSI,其哈希键名为 'subscriberIndustryId'。 Industry.subscribers 解析器应该查询 "subscriberIndustryId = $ctx.source.id" 所在的索引。如果您不使用 CLI 和 @connection,您也可以自己实现此模式。
这应该可以解决问题:
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "subscriberIndustryId"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
},
"index": "gsi-IndustrySubscribers"
我是 aws 和 graphql 的新手。我正在研究 appsync 并尝试在两种类型之间建立关系。以下是我的架构:
type BadCustomer {
id: ID!
name: String!
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
type BadCustomerConnection {
items: [BadCustomer]
nextToken: String
}
input CreateBadCustomerInput {
name: String!
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
input CreateDamageInput {
damage: Float!
comment: String
}
input CreateIndustryInput {
name: String!
}
input CreateSubscriberInput {
name: String!
email: AWSEmail!
phone: AWSPhone
streetAddress: String!
subscriberIndustryId: ID!
}
type Damage {
id: ID!
customer: BadCustomer!
industry: Industry!
victim: Subscriber!
damage: Float!
comment: String
}
type DamageConnection {
items: [Damage]
nextToken: String
}
input DeleteBadCustomerInput {
id: ID!
}
input DeleteDamageInput {
id: ID!
}
input DeleteIndustryInput {
id: ID!
}
input DeleteSubscriberInput {
id: ID!
}
type Industry {
id: ID!
name: String!
subscribers(
filter: TableSubscriberFilterInput,
sortDirection: ModelSortDirection,
limit: Int,
nextToken: String
): SubscriberConnection
}
type IndustryConnection {
items: [Industry]
nextToken: String
}
enum ModelSortDirection {
ASC
DESC
}
type Mutation {
createIndustry(input: CreateIndustryInput!): Industry
updateIndustry(input: UpdateIndustryInput!): Industry
deleteIndustry(input: DeleteIndustryInput!): Industry
createSubscriber(input: CreateSubscriberInput!): Subscriber
updateSubscriber(input: UpdateSubscriberInput!): Subscriber
deleteSubscriber(input: DeleteSubscriberInput!): Subscriber
createBadCustomer(input: CreateBadCustomerInput!): BadCustomer
updateBadCustomer(input: UpdateBadCustomerInput!): BadCustomer
deleteBadCustomer(input: DeleteBadCustomerInput!): BadCustomer
createDamage(input: CreateDamageInput!): Damage
updateDamage(input: UpdateDamageInput!): Damage
deleteDamage(input: DeleteDamageInput!): Damage
}
type Query {
getIndustry(id: ID!): Industry
listIndustries(filter: TableIndustryFilterInput, limit: Int, nextToken: String): IndustryConnection
getSubscriber(id: ID!): Subscriber
listSubscribers(filter: TableSubscriberFilterInput, limit: Int, nextToken: String): SubscriberConnection
getBadCustomer(id: ID!): BadCustomer
listBadCustomers(filter: TableBadCustomerFilterInput, limit: Int, nextToken: String): BadCustomerConnection
getDamage(id: ID!): Damage
listDamages(filter: TableDamageFilterInput, limit: Int, nextToken: String): DamageConnection
}
type Subscriber {
id: ID!
name: String!
email: AWSEmail!
phone: AWSPhone
streetAddress: String!
industry: Industry!
}
type SubscriberConnection {
items: [Subscriber]
nextToken: String
}
type Subscription {
onCreateIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["createIndustry"])
onUpdateIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["updateIndustry"])
onDeleteIndustry(id: ID, name: String): Industry
@aws_subscribe(mutations: ["deleteIndustry"])
onCreateSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["createSubscriber"])
onUpdateSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["updateSubscriber"])
onDeleteSubscriber(
id: ID,
name: String,
email: AWSEmail,
phone: AWSPhone,
streetAddress: String
): Subscriber
@aws_subscribe(mutations: ["deleteSubscriber"])
onCreateBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["createBadCustomer"])
onUpdateBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["updateBadCustomer"])
onDeleteBadCustomer(
id: ID,
name: String,
phone: AWSPhone,
email: AWSEmail,
streetAddress: String
): BadCustomer
@aws_subscribe(mutations: ["deleteBadCustomer"])
onCreateDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["createDamage"])
onUpdateDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["updateDamage"])
onDeleteDamage(id: ID, damage: Float, comment: String): Damage
@aws_subscribe(mutations: ["deleteDamage"])
}
input TableBadCustomerFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
phone: TableStringFilterInput
email: TableStringFilterInput
streetAddress: TableStringFilterInput
dob: TableStringFilterInput
passportNumber: TableStringFilterInput
driversLicenceNumber: TableStringFilterInput
ipAddress: TableStringFilterInput
}
input TableBooleanFilterInput {
ne: Boolean
eq: Boolean
}
input TableDamageFilterInput {
id: TableIDFilterInput
damage: TableFloatFilterInput
comment: TableStringFilterInput
}
input TableEventFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
where: TableStringFilterInput
when: TableStringFilterInput
description: TableStringFilterInput
}
input TableFloatFilterInput {
ne: Float
eq: Float
le: Float
lt: Float
ge: Float
gt: Float
contains: Float
notContains: Float
between: [Float]
}
input TableIDFilterInput {
ne: ID
eq: ID
le: ID
lt: ID
ge: ID
gt: ID
contains: ID
notContains: ID
between: [ID]
beginsWith: ID
}
input TableIndustryFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
}
input TableIntFilterInput {
ne: Int
eq: Int
le: Int
lt: Int
ge: Int
gt: Int
contains: Int
notContains: Int
between: [Int]
}
input TableStringFilterInput {
ne: String
eq: String
le: String
lt: String
ge: String
gt: String
contains: String
notContains: String
between: [String]
beginsWith: String
}
input TableSubscriberFilterInput {
id: TableIDFilterInput
name: TableStringFilterInput
email: TableStringFilterInput
phone: TableStringFilterInput
streetAddress: TableStringFilterInput
}
input UpdateBadCustomerInput {
id: ID!
name: String
phone: AWSPhone
email: AWSEmail
streetAddress: String
dob: AWSDate
passportNumber: String
driversLicenceNumber: String
ipAddress: AWSIPAddress
}
input UpdateDamageInput {
id: ID!
damage: Float
comment: String
}
input UpdateIndustryInput {
id: ID!
name: String
}
input UpdateSubscriberInput {
id: ID!
name: String
email: AWSEmail
phone: AWSPhone
streetAddress: String
subscriberIndustryId: ID
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
我想在 Subscribers
和 Industry
之间建立关系。每个订户属于一个行业。我为 Subscriber.industry
和 Industry.subscribers
设置了解析器。
Subscriber.industry
解析器,数据源Industry
table:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.subscriberIndustryId, "___xamznone____"))
}
}
Industry.subscribers
解析器,数据源Subscriber
table:
#set( $limit = $util.defaultIfNull($context.args.limit, 10) )
{
"version": "2017-02-28",
"operation": "Query",
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "id"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
},
"scanIndexForward": #if( $context.args.sortDirection )
#if( $context.args.sortDirection == "ASC" )
true
#else
false
#end
#else
true
#end,
"filter": #if( $context.args.filter )
$util.transform.toDynamoDBFilterExpression($ctx.args.filter)
#else
null
#end,
"limit": $limit,
"nextToken": #if( $context.args.nextToken )
"$context.args.nextToken"
#else
null
#end
}
我有以下疑问:
query ListIndustries {
listIndustries {
items {
id
name
subscribers {
items {
id
name
streetAddress
}
}
}
}
}
query ListSubscribers {
listSubscribers{
items {
id
name
industry {
name
}
}
}
}
如果我 运行 ListSubscribers
在 appsync 控制台上查询,它会给我想要的结果,例如:
{
"data": {
"listSubscribers": {
"items": [
{
"id": "d04d6ef4-95bf-4b01-9a6a-13f550dbfa8f",
"name": "John Doe",
"industry": {
"name": "Real Estate"
}
},
{
"id": "96fa3e60-fdcf-4a6d-a3b6-72ec2c4701d1",
"name": "Jane Doe",
"industry": {
"name": "Ecommerce"
}
},
{
"id": "413dd506-afd4-474e-a850-54a39eb1eeeb",
"name": "John Doe",
"industry": {
"name": "Real Estate"
}
}
]
}
}
}
但是如果我 运行 ListIndustries
查询,它不会给我该行业的订阅者列表,例如:
{
"data": {
"listIndustries": {
"items": [
{
"id": "b904d8f3-b504-48e0-b28f-0f9ac1742186",
"name": "Real Estate",
"subscribers": {
"items": []
}
},
{
"id": "167b87f2-3342-4390-80af-df53ba3c6f73",
"name": "Ecommerce",
"subscribers": {
"items": []
}
}
]
}
}
}
需要有人帮我解决这个问题。
我在 Industry.subscribers
解析器中错过了 index
。添加它解决了问题。
我需要更多信息才能确定,但看起来 Industry.subscribers 解析器可能配置错误。您的查询表达式当前指定:
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "id"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
}
// There is no "index" so this is trying to query the primary index.
也就是说,"Query the primary index where the 'id' = $ctx.source.id"。根据您粘贴的对象,看起来您的订阅者对象使用 $util.autoId()
,因此订阅者 'id' 永远不会等于行业 'id'。如果使用 Amplify CLI 的 @connection 指令,默认情况下将在订阅者 table 上创建一个 GSI,其哈希键名为 'subscriberIndustryId'。 Industry.subscribers 解析器应该查询 "subscriberIndustryId = $ctx.source.id" 所在的索引。如果您不使用 CLI 和 @connection,您也可以自己实现此模式。
这应该可以解决问题:
"query": {
"expression": "#connectionAttribute = :connectionAttribute",
"expressionNames": {
"#connectionAttribute": "subscriberIndustryId"
},
"expressionValues": {
":connectionAttribute": {
"S": "$context.source.id"
}
}
},
"index": "gsi-IndustrySubscribers"