在 AWS AppSync 中为 SQL 查询字符串化 JSON 对象

Posted

技术标签:

【中文标题】在 AWS AppSync 中为 SQL 查询字符串化 JSON 对象【英文标题】:Stringify JSON object for SQL query in AWS AppSync 【发布时间】:2020-10-12 13:13:11 【问题描述】:

问题:如何在我的 Appsync 速度模板中为 SQL 语句字符串化 JSON 对象?

说明:我有一个 Aurora RDS 表,其中有一列数据类型为 JSON。 AppSync API 已连接到 RDS。 我的 GraphQL 架构看起来像

input CreateServiceCatalogItemInput 
    serviceName: String!
    serviceConfig: ServiceConfigInput!


type Mutation 
    createServiceCatalogItem(input: CreateServiceCatalogItemInput!): ServiceCatalogItem


type Query 
    getAllServiceCatalogItem: [ServiceCatalogItem]


type ServiceCatalogItem 
    serviceId: ID!
    serviceName: String!
    serviceConfig: ServiceConfig!


type ServiceConfig 
    connectionType: String
    capacity: Int


input ServiceConfigInput 
    connectionType: String
    capacity: Int


schema 
    query: Query
    mutation: Mutation

我的 createServiceCatalogItem 突变解析器看起来像


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toString($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

这引发了我的错误:

在 com.amazonaws.deepdish.transform.util.TransformUtils 类中调用方法 'toString' 抛出异常 java.lang.IllegalArgumentException: wrong number of arguments at ...

如果我这样做:


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toJson($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

这引发了我的错误:

无法解析 JSON 文档:'Unexpected character ('c' (code 99)): was Expecting comma to split Array entries\n at ...

如果我这样做:


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$ctx.args.input.serviceConfig') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

然后我得到一个有道理的错误:

RDSHttp:"message":"错误:json 类型的输入语法无效\n 详细信息:令牌 \"connectionType\" 无效。\n 位置:222\n 其中:JSON 数据,第 1 行: connectionType..."

但是,当我在解析器中对 JSON 进行硬编码时,它可以工作:


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '\"connectionType\":\"ftth\",\"capacity\":1') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

那么如何将 connectionType=ftth, capacity=1 转换为 "connectionType":"ftth", "capacity":1?我做错了什么或者我错过了什么?任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

解决方案 1

感谢@cyberwombat,我能够解决这个问题。如果有人需要,我将其发布为参考。

我的serviceConfig 对象不是固定的,可能会随着时间而改变,所以我修改了我的解析器以使其更通用,它看起来像这样:

#set($serviceConfigMap = )

#foreach($key in $ctx.args.input.serviceConfig.keySet())
    $util.qr($serviceConfigMap.put("$key", $ctx.args.input.serviceConfig.get($key)))
#end

#set($serviceConfigMap = $util.toJson($serviceConfigMap))


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapejavascript($serviceConfigMap)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

旧解决方案

这是我之前解决这个问题的方法。

我将解析器转换为 Pipeline,并在 NodeJS 中创建了一个简单的 Lambda 函数来对 JSON 对象进行字符串化。这就是我的 lambda 函数的样子:

exports.handler = (event, context, callback) => 

    const response = 
        statusCode: 200,
        body: JSON.stringify(event.input.serviceConfig).replace(/\"/g, '\\\"'),
    ;
    callback(null, response)
;

这就是 serviceConfig 现在的样子,也是我想要的样子:

\"connectionType\":\"ftth\",\"maxUploadCapacity\":1"

我现在可以在解析器中的 SQL 语句中轻松使用它。

【讨论】:

【参考方案2】:

你可以像这样构建一个 JSON 变量:

#set($json = $util.toJson(
  "connectionType": "$ctx.args.input.serviceConfig.connectionType",
  "capacity": $ctx.args.input.serviceConfig.capacity
  ))

并插入您的查询:


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($json)' RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

由于所有引号和转义,上述内容有点挑战性,但我认为使用 escapeJavaScript 可以解决问题。

或直接:


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '\"connectionType\":\"$ctx.args.input.serviceConfig.connectionType\",\"capacity\": $ctx.args.input.serviceConfig.capacity') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]

【讨论】:

你是最棒的。你的解决方案奏效了!!由于我的 JSON 不仅固定为 connectionType 和容量键,因此我稍微修改了您的解决方案。如果有人需要,我会发布我的解决方案以供参考。非常感谢!!

以上是关于在 AWS AppSync 中为 SQL 查询字符串化 JSON 对象的主要内容,如果未能解决你的问题,请参考以下文章

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

如何通过 AWS AppSync 客户端将保存字符串的变量传递给 GraphQL 查询?

AWS AppSync:如何通过 DynamoDB 返回有效的 JSON

AWS AppSync - 从 AppSync 控制台运行时的 GraphQL 查询超时

如何使用 AWS appsync (GraphQL) 禁用自省查询?

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