用于塑造响应数据的 AWS AppSync 查询(类似于 SQL 中的 Group By)

Posted

技术标签:

【中文标题】用于塑造响应数据的 AWS AppSync 查询(类似于 SQL 中的 Group By)【英文标题】:AWS AppSync Query to shape response data (Similar to Group By in SQL) 【发布时间】:2018-09-18 06:14:09 【问题描述】:

我有一个 DynamoDB 表,其中包含客户端所需的所有数据,但是,我想调整客户端接收到的数据以减少客户端操作。

我的架构:

type StateCounty 
    id: ID!
    StateName: String
    CountyName: String
    FIPSST: Int
    FIPSCNTY: Int   
    Penetration: String
    Date: String


要返回自定义查询,我有以下类型:

type Query 
  getStateCountybyState(StateName: String): StateCountyConnection

这可行 - 并且只需一个简单的查询

query  getStateCountybyState 
     getStateCountybyState (StateName: "Delaware")   
      items  
       StateName
       CountyName
       Date    

    
   
   

结果按预期返回:

 
      "StateName": "Delaware",
      "CountyName": "Kent",
      "Date": "02-01-2017"
    ,
    
      "StateName": "Delaware",
      "CountyName": "Sussex",
      "Date": "02-01-2016"
    ,
    
      "StateName": "Delaware",
      "CountyName": "New Castle",
      "Date": "02-01-2018"
  

等等

我想按以下格式返回数据:

 
   "StateName": "Delaware" 

      "CountyName": "Kent",
      "Date": "02-01-2017"
      ,
     
      "CountyName": "Sussex",
      "Date": "02-01-2016"
     ,
     
      "CountyName": "New Castle",
      "Date": "02-01-2018"
     
 

我已尝试将 GroupCounty: [StateCountyGroup] 添加到架构中:

type StateCounty 
    id: ID!
    StateName: String
    CountyName: String
    FIPSST: Int
    FIPSCNTY: Int   
    Penetration: String
    Date: String
    GroupCounty: [StateCountyGroup]

然后是查询中的引用

query  getStateCountybyState 
     getStateCountybyState (StateName: "Delaware")   
      items  
       StateName
       CountyName
       Date  
       GroupCounty: [StateCountyGroup] 
    
   
   

我认为我的问题在解析器中 - 目前,它被配置为使用 StateName 作为键,但我不确定如何将 StateName 从主查询传递到子查询。

解析器:


    "version" : "2017-02-28",
    "operation" : "Query",
    "query" : 
        "expression" : "StateName = :StateName",
        "expressionValues" : 
            ":StateName" :  "S" : "$context.arguments.StateName" ,
        
    ,
    "index" : "StateName-index-copy",
    "select" : "ALL_ATTRIBUTES",


感谢任何指导 - 我已经多次阅读文档,但找不到示例。

更新

我尝试了 Richard 下面的建议 - 它绝对是在正确的轨道上,但是,尽管主题有多种变化,我要么返回 null 要么返回以下错误(我消除了错误中返回的一些县对象简洁):

"message": "Unable to convert set($myresponse = \n  \"Delaware\": 
[SSA=8000, Eligibles=32295, FIPS=10001, StateName=Delaware, SSACNTY=0, 
Date=02-01-2016, CountyName=Kent, Enrolled=3066, Penetration=0.0949, 
FIPSCNTY=1, FIPSST=10, SSAST=8, id=6865, 
SSA=8010, Eligibles=91332, FIPS=10003, StateName=Delaware, SSACNTY=10, Date=02-01-2016, CountyName=New Castle, Enrolled=10322, Penetration=0.113, FIPSCNTY=3, FIPSST=10, SSAST=8, id=6866, 
SSA=0, Eligibles=10, FIPS=10, StateName=Delaware, SSACNTY=0, Date=02-01-2018, CountyName=Pending County Designation, Enrolled=0, Penetration=0, FIPSCNTY=0, FIPSST=10, SSAST=0, id=325, 
SSA=8000, Eligibles=33371, FIPS=10001, StateName=Delaware, SSACNTY=0, Date=02-01-2017, CountyName=Kent, Enrolled=3603, Penetration=0.108, FIPSCNTY=1, FIPSST=10, SSAST=8, id=3598, 
SSA=8020, Eligibles=58897, FIPS=10005, StateName=Delaware, SSACNTY=20, Date=02-01-2016, CountyName=Sussex, Enrolled=3760, Penetration=0.0638, FIPSCNTY=5, FIPSST=10, SSAST=8, id=6867)    \nnull\n\n to class java.lang.Object."
        
      ]
    

【问题讨论】:

【参考方案1】:

通过阅读以上内容,听起来您的原始查询正在返回您想要的正确结果,但不是您希望的响应格式,因为您希望“StateName”成为*** JSON 键该值是您作为参数传入的状态的 JSON 对象。那准确吗?如果是这样,那么为什么不使用已经有效但使用不同响应模板的相同查询。比如:

#set($myresponse = 
  "$ctx.args.StateName": $ctx.result.items
)    
$util.toJson($myresponse)

请注意,$myresponse 与您在上面的示例不完全相同,"stateName" : "Delaware" ... 不是完全有效的 JSON,所以我不想假设一个好的结构会是什么,但是如果您已经从查询中获得了正确的结果,那么重点仍然存在,我只会尝试更改 GraphQL 结果的结构。

现在,如果我误读了上述内容并且您没有从查询中获得正确的结果,那么我可以阅读您的“主要查询到子查询”语句的另一种方式是您正在尝试应用额外的 @ 987654325@ 到您的查询结果。如果是这种情况,那么你需要这样的东西:


    "version" : "2017-02-28",
    "operation" : "Query",
    "query" : 
        "expression" : "StateName = :StateName",
        "expressionValues" : 
            ":StateName" :  "S" : "$context.arguments.StateName" ,
        
    ,
    "index" : "StateName-index-copy",
    "select" : "ALL_ATTRIBUTES",
    "filter" : 
      "expression" : "#population >= :population",
      "expressionNames" : 
        "#population" : "population"
      ,
      "expressionValues" : 
        ":population" : $util.dynamodb.toDynamoDBJson($ctx.args.population)
      
    

我在这里使用了一个示例,您的查询可能还需要按每个县的人口规模进行过滤。这可能无法代表您正在寻找的内容,但希望对您有所帮助。

已于 2018 年 4 月 16 日编辑更多信息

我已逐步编写了有关此的更多信息,以逐个了解这些概念。

这里的关键不仅是响应模板,还包括您请求返回的字段(因为这是 GraphQL 的本质)。让我们通过示例来了解一下。现在您正在使用 GraphQL 返回单个项目(因为您的响应模板正在将数组转换为单个项目),因此您需要更改预期的 GraphQL 查询响应类型。假设您的架构中有一个 GraphQL 类型,如下所示:

type State 
    id: ID!
    population: String!
    governor: String!


type Query 
    allStates: [State]

如果你只是像上面那样转换模板中的响应,你会看到类似“类型不匹配错误,预期类型 LIST”这样的错误:

query 
  allStates
    id
    population
  

这是因为您的回复不再返回单个项目。相反,您需要更改 GraphQL 响应类型 [State] 以匹配您的模板转换正在执行的操作 State,如下所示:

type State 
    StateName: String


type Query 
    allStates: State

现在,如果您的解析器 request 模板正在执行返回项目列表的操作(如 DynamoDB 扫描或查询),您可以将列表转换为 响应中的单个项目 像这样的模板:

#set($convert = "StateName" : $ctx.result.items )
$util.toJson($convert)

然后运行以下 GraphQL 查询:

query 
  allStates
    StateName
  

您将得到一个包含结果数组的单个对象:


  "data": 
    "allStates": 
      "StateName": "[id=1, population=10000, governor=John Smith]"
    
  

但是,虽然这可能会指出您遇到的错误,但这会返回 StateName 并且从您最初的问题来看,我认为您希望通过组合响应中的记录以进行一些优化,以及一些潜在的过滤。一种方法是创建一个数组(或者您可以创建一个地图 )并根据某些条件填充它。例如,修改您的查询以将 StateName 作为参数:

type Query 
    allStates(StateName: String!): Post

然后您可以在解析器响应模板中对此进行过滤,方法是使用#foreach#if() 条件,然后仅当响应中的项目符合您请求的状态时才调用.add()

#set($convert = "StateName" : [] )
#foreach($item in $ctx.result.items)
  #if($item["StateName"]=="$ctx.args.StateName")
    $util.qr($convert.get("StateName").add("$item"))
  #end
#end
$util.toJson($convert)

所以现在你可以像这样运行:

query 
  allStates(StateName:"Texas")
    StateName
  

这将只返回您作为参数传递的特定状态的结果。但是您会注意到查询的选择集是StateName。您可以通过在 GraphQL 类型中列出可能的状态来引入更多的灵活性:

type State 
    StateName: String
    Seattle: String
    Texas: String

现在您更改解析器响应模板以使用参数来构建返回数组,因为它可以在选择集中指定它:

#set($convert = "$ctx.args.StateName" : [] )
#foreach($item in $ctx.result.items)
  #if($item["StateName"]=="$ctx.args.StateName")
    $util.qr($convert.get("$ctx.args.StateName").add("$item"))
  #end
#end
$util.toJson($convert)

所以我可以运行这个查询:

query 
  allPosts(StateName:"Seattle")
    Seattle
  

我得到了我的结果。请注意,虽然将Seattle 作为参数传递但请求返回Texas

query 
  allPosts(StateName:"Seattle")
    Texas
  

这将不起作用,因为您在地图中创建的响应对象是 Seattle: [...],但您将 Texas 作为选择集。

您可能想要做的最后一件事是返回多个状态,您可以通过构建一个以状态名称为键的巨型地图来实现,或者通过将状态名称添加到使用参数或选择集来完成返回类型如上所示。这取决于你,所以我不确定你会如何想要它,但希望这能展示你如何操纵响应来满足你的需求。

【讨论】:

非常感谢@Richard 为我指明了正确的方向,在 Response 映射中塑造数据是有意义的,我正在尝试一些选项,将发布最终结果今天晚些时候对我有用的版本。 我肯定在使用 Velocity 模板语言 - 无法解决 - 我收到一条错误消息,其中显示了正确 StateName 的对象数组 - 我尝试了多种变体来查看它是否正确是解析问题。错误添加到原始帖子中。 @AshleyW 我对回复进行了一些编辑,希望对您有所帮助。我认为你添加到最后的错误与使用地图和数组有关,你需要建立一些不同的东西。我还建议阅读此编程指南:docs.aws.amazon.com/appsync/latest/devguide/… - 非常感谢您抽出宝贵时间提供如此详细的回复!真的很感激。

以上是关于用于塑造响应数据的 AWS AppSync 查询(类似于 SQL 中的 Group By)的主要内容,如果未能解决你的问题,请参考以下文章

即使禁用离线,AWS AppSync 查询也会返回缓存响应

用于 AWS AppSync 中的异步计算的 Graphql 订阅

AWS Appsync Javascript 查询示例和输入语法

在 AWS AppSync 查询中返回嵌套 JSON

AWS AppSync 中的 InvalidUserPoolException

AWS AppSync 响应排序结果?