AWS Appsync 批处理解析器

Posted

技术标签:

【中文标题】AWS Appsync 批处理解析器【英文标题】:AWS Appsync Batch Resolver 【发布时间】:2019-02-03 19:01:30 【问题描述】:

为此苦苦挣扎了一段时间,并且应用程序我将问题的查询名称更改为 getDeviceReadings,我一直在使用 getAllUserDevices(抱歉有任何混淆)

type Device 
   id: String
   device: String!


type Reading 
   device: String
   time: Int


type PaginatedDevices 
   devices: [Device]
   readings: [Reading]
   nextToken: String


type Query 
   getDevicesReadings(nextToken: String, count: Int): PaginatedDevices

然后我在查询 getDevicesReadings 上有一个解析器,它可以正常工作并返回用户迄今为止拥有的所有设备


"version": "2017-02-28",
"operation": "Query",
"query" : 
  "expression": "id = :id",
    "expressionValues" : 
      ":id" :  "S" : "$context.identity.username" 
    

#if( $context.arguments.count )
    ,"limit": $context.arguments.count
#end
#if( $context.arguments.nextToken )
    ,"nextToken": "$context.arguments.nextToken"
#end

现在我想根据源结果返回设备的所有读数,所以我有一个关于 getDevicesReadings/readings 的解析器

#set($ids = [])
#foreach($id in $ctx.source.devices)
  #set($map = )
  $util.qr($map.put("device", $util.dynamodb.toString($id.device)))
  $util.qr($ids.add($map))
#end


"version" : "2018-05-29",
"operation" : "BatchGetItem",
 "tables" : 
    "readings": 
        "keys": $util.toJson($ids),
        "consistentRead": true
    
  

使用这样的响应映射..

$utils.toJson($context.result.data.readings)

我运行一个查询

query getShit
  getDevicesReadings
    devices
      device
     
    readings
      device
      time
    
  

这会返回以下结果


  "data": 
    "getAllUserDevices": 
     "devices": [
       
         "device": "123"
       ,
       
         "device": "a935eeb8-a0d0-11e8-a020-7c67a28eda41"
       
     ],
     "readings": [
       null,
       null
     ]
   
 

正如您在图像上看到的,主分区键是读数表上的设备,我查看了日志,我有以下内容

抱歉,如果您无法阅读日志,它基本上说有未处理的密钥

以及以下错误信息

"message": "The provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 0H21LJE234CH1GO7A705VNQTJVVV4KQNSO5AEMVJF66Q9ASUAAJG)",

我猜我的映射不太正确,我将读数作为我的键传递?

非常感谢任何帮助

【问题讨论】:

【参考方案1】:

不,当您有主排序键时,您绝对可以使用批处理解析器。您的示例中的错误是您没有向解析器提供主排序键。

此代码需要提供“时间”和“设备”,因为您需要两者都完全指定主键。

#set($ids = [])
#foreach($id in $ctx.source.devices)
  #set($map = )
  $util.qr($map.put("device", $util.dynamodb.toString($id.device)))
  $util.qr($ids.add($map))
#end

你应该有类似的东西:

#set($ids = [])
#foreach($id in $ctx.source.devices)
  #set($map = )
  # The tables primary key is made up of "device" AND "time"
  $util.qr($map.put("device", $util.dynamodb.toString($id.device)))
  $util.qr($map.put("time", $util.dynamodb.toString($id.time)))
  $util.qr($ids.add($map))
#end

如果您想获取许多共享相同“设备”值但具有不同“时间”值的记录,则需要使用 DynamoDB 查询操作,而不是批量获取。

【讨论】:

【参考方案2】:

您是对的,您提供的请求映射模板与readings 表上的主键不匹配。 BatchGetItem 期望 keys 是主键,但是您只传递哈希键。

要使BatchGetItem 调用成功,您必须传递散列和排序键,因此在这种情况下,devicetime 属性。

也许readings 表上的Query 会更合适?

【讨论】:

感谢您和 mparis 的回答让我正确,我将在 mparis 举个例子时给出答案。再次感谢各位!嘿,额外的道具,如果你能告诉我将 appsync VTL 解析器与 lambda 解析器相对放置是否有任何优势 嗨 Tinou,你看到我是如何循环然后在我的 lambda 函数中扩展列表的,我将如何在查询中使用 VTL 来做到这一点?我将作为一个单独的问题提出 别担心,同一个团队!如果您使用 Lambda 解析程序,您需要引入一个中间步骤来查询您的 DynamoDB 表。如果您在 AppSync 中使用 DynamoDB 解析器,您的请求生命周期将是 AppSync -> Lambda -> DynamoDB vs AppSync -> DynamoDB。这意味着 GraphQL 查询的整体延迟将会增加。对于更复杂的工作流程,使用 Lambda 解析器应该会给您更多的控制权。 非常感谢 Tinou,非常感谢您花时间回答。我在这里问了一个问题***.com/questions/52086862/aws-appsync-query-resolver我问的可能吗?【参考方案3】:

所以当你有主排序键时你不能有批处理解析器?!

所以答案是创建一个 lambda 函数并将其作为我的解析器

import boto3
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):

   list = []
   for device in event['source']['devices'] :
       dynamodb = boto3.resource('dynamodb')
       readings  = dynamodb.Table('readings')
       response = readings.query(
           KeyConditionExpression=Key('device').eq(device['device'])
       )
       items = response['Items']
       list.extend(items)
   return list

【讨论】:

以上是关于AWS Appsync 批处理解析器的主要内容,如果未能解决你的问题,请参考以下文章

AWS AppSync Lambda 解析器获取查询返回类型

AWS appsync 查询解析器

AWS AppSync 解析器内部超时配置

用于 ElasticSearch 服务的简单 AWS AppSync 架构和解析器

在子解析器 AWS AppSync 中获取父对象

AWS AppSync Lambda 解析器字段