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

时间:2018-04-08 21:21:13

标签: amazon-dynamodb graphql aws-appsync

我有一个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",

}

任何指导意见 - 我已多次浏览文档,但找不到示例。

更新

我尝试了理查德的以下建议 - 它肯定是在正确的轨道上,但是,尽管主题有多种变化,我要么返回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 个答案:

答案 0 :(得分:2)

通过阅读上述内容,听起来您的原始查询返回了您想要的正确结果,但不是您希望的响应格式,因为您希望" StateName"是一个顶级JSON键,其值是您作为参数传入的状态的JSON对象。那是准确的吗?如果是这样,那么为什么不使用已经工作但具有不同响应模板的相同查询。类似的东西:

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

请注意,$myresponse与上面的内容完全相同,因为"stateName" : "Delaware" { ... }的示例并不是完全有效的JSON,所以我不想制作一个关于什么是好的结构的假设,但如果你已经从你的查询中获得了正确的结果,那么我只会尝试改变你的GraphQL结果的结构。

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

{
    "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)
      }
    }
}

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

以更多信息编辑4/16/18

我已经逐步地写了更多关于此的信息,以便逐步完成这些概念。

这里的关键不仅仅是响应模板,还包括您要求返回的字段(因为这是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
}

现在,如果您的解析器请求模板正在执行返回项目列表(如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并且从原始问题开始,我认为您希望通过在响应中组合记录来进行一些优化,以及一些潜在的过滤。一种方法是创建一个数组(或者你可以创建一个map {})并根据一些条件填充它。例如,修改您的查询以将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作为选择集。

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