如何处理 aws-appsync 中的关系?

Posted

技术标签:

【中文标题】如何处理 aws-appsync 中的关系?【英文标题】:How to work with relationships in aws-appsync? 【发布时间】:2019-08-14 04:31:12 【问题描述】:

我是 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

我想在SubscribersIndustry 之间建立关系。每个订阅者都属于一个行业。我为Subscriber.industryIndustry.subscribers 设置了解析器。

Subscriber.industry解析器,数据源Industry表:


    "version": "2017-02-28",
    "operation": "GetItem",
    "key": 
        "id": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.subscriberIndustryId, "___xamznone____"))
    

Industry.subscribers解析器,数据源Subscriber表:

#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
      
    
  

如果我在 appsync 控制台上运行 ListSubscribers 查询,它会给我想要的结果,例如:


  "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": []
          
        
      ]
    
  

需要有人可以帮我解决这个问题。

【问题讨论】:

【参考方案1】:

我需要更多信息才能确定,但​​看起来 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.

其中说,“查询 'id' = $ctx.source.id 的主索引”。根据您粘贴的对象,您的订阅者对象似乎使用$util.autoId(),因此订阅者“id”永远不会等于行业“id”。如果使用 Amplify CLI 的 @connection 指令,将在订阅者表上创建一个 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"

【讨论】:

【参考方案2】:

我在Industry.subscribers 解析器中错过了index。添加它可以解决问题。

【讨论】:

以上是关于如何处理 aws-appsync 中的关系?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 Redux 中的关系数据?

如何处理数据仓库中的图关系?

如何处理mongodb中的多对多关系

如何处理 JSON 中的多对多关系?

如何处理MongoDB中的多对多关系?

如何处理没有其他关系的实体中的嵌套对象