如何使用 AppSync 解析器和 Aurora 将可选字段插入为空?

Posted

技术标签:

【中文标题】如何使用 AppSync 解析器和 Aurora 将可选字段插入为空?【英文标题】:How do I insert an optional field as null using AppSync Resolvers and Aurora? 【发布时间】:2019-04-23 02:47:45 【问题描述】:

我有一个可选的字符串字段,notes,它有时是空的。如果为空我要插入null,否则我要插入字符串。

这是我的解析器 -


    "version" : "2017-02-28",
    "operation": "Invoke",
        #set($id = $util.autoId())
        #set($notes = $util.defaultIfNullOrEmpty($context.arguments.notes, 'null'))

        "payload": 
          "sql":"INSERT INTO things VALUES ('$id', :NOTES)",
          "variableMapping": 
            ":NOTES" : $notes
          ,
          "responseSQL": "SELECT * FROM things WHERE id = '$id'"
        

有了这个graphql

mutation CreateThing
  createThing() 
    id
    notes
  

我明白了-


  "data": 
    "createRoll": 
      "id": "6af68989-0bdc-44e2-8558-aeb4c8418e93",
     "notes": "null"
   
 

当我真的想要 null 不带引号时。

有了这个graphql -

mutation CreateThing
  createThing(notes: "Here are some notes") 
    id
    notes
  

我明白了-


  "data": 
    "createThing": 
      "id": "6af68989-0bdc-44e2-8558-aeb4c8418e93",
      "notes": "Here are some notes"
    
  

这就是我想要的。

如何将无引号的 null 和带引号的字符串放入同一字段?

【问题讨论】:

【参考方案1】:

我们正在研究同样的问题。出于某种原因,接受的答案对我们不起作用。可能是因为它是一个测试版功能并且有一个新的解析器版本(2018-05-29 与 2017-02-28,此处更改:Resolver Mapping Template Changelog)。

我们暂时用这个用NULLIF():


    "version": "2018-05-29",
    "statements": [
        "INSERT INTO sales_customers_addresses (`id`, `customerid`, `type`, `company`, `country`, `email`) VALUES (NULL, :CUSTOMERID, :TYPE, NULLIF(:COMPANY, ''), NULLIF(:COUNTRY, ''), :EMAIL)"
    ],
    "variableMap": 
        ":CUSTOMERID": $customerid,
        ":TYPE": "$type",
        ":COMPANY": "$util.defaultIfNullOrEmpty($context.args.address.company, '')",
        ":COUNTRY": "$util.defaultIfNullOrEmpty($context.args.address.country, '')",
        ":EMAIL": "$context.args.address.email"
    

【讨论】:

我的答案是使用 2017-02-28 版本,因为它与 Lambda 数据源而非 RDS 数据源相关联。 Lambda 支持 2017-02-28 和 2018-05-29 版本。此处发布的原始问题遵循本教程 github.com/aws-samples/aws-appsync-rds-aurora-sample 。它使用 Lambda 作为 AppSync 数据源来代理 RDS 调用。本教程是在 AppSync 原生支持 RDS 之前创建的,根据您的用例,现在直接使用 RDS 数据源可能更有意义。【参考方案2】:

TL;DR您应该使用$util.toJson() 正确打印$context.arguments.notes。用

替换您的 $notes 分配
#set($notes = $util.toJson($util.defaultIfNullOrEmpty($context.arguments.notes, null)))

说明:

原因是 VTL 会打印 toString() 方法返回的任何内容以及您对 $util.defaultIfNullOrEmpty($context.arguments.notes, 'null') 将返回字符串"null",将打印为"null"

如果您替换为$util.defaultIfNullOrEmpty($context.arguments.notes, null),那么它将返回一个null 字符串。但是,VTL 将打印$notes,因为这是它处理null 引用的方式。为了打印null,这是null 的有效JSON 表示,我们必须将其序列化为JSON。所以正确的说法是:

#set($notes = $util.toJson($util.defaultIfNullOrEmpty($context.arguments.notes, null)))

全面测试:

我假设您从 AWS AppSync 控制台中提供的 RDS 示例开始并对其进行了修改。为了重现,我将 Schema 中的 content 字段更新为可为空:

type Mutation 
   ...
   createPost(author: String!, content: String): Post
   ...

type Post 
    id: ID!
    author: String!
    content: String
    views: Int
    comments: [Comment]

我修改了posts 表架构,因此content 在那里也可以为空:(在 Lambda 函数内部)

function conditionallyCreatePostsTable(connection) 
  const createTableSQL = `CREATE TABLE IF NOT EXISTS posts (
    id        VARCHAR(64) NOT NULL,
    author    VARCHAR(64) NOT NULL,
    content   VARCHAR(2048),
    views     INT NOT NULL,
    PRIMARY KEY(id))`;
  return executeSQL(connection, createTableSQL);

这是createPost 突变的请求模板:

    
    "version" : "2017-02-28",
    "operation": "Invoke",
    #set($id = $util.autoId())   
    "payload": 
      "sql":"INSERT INTO posts VALUES ('$id', :AUTHOR, :CONTENT, 1)",
      "variableMapping": 
        ":AUTHOR" : "$context.arguments.author",
        ":CONTENT" : $util.toJson($util.defaultIfNullOrEmpty($context.arguments.content, null))
      ,
      "responseSQL": "SELECT id, author, content, views FROM posts WHERE id = '$id'"
    

和响应模板:

$util.toJson($context.result[0])

以下查询:

mutation CreatePost 
  createPost(author: "Me") 
    id
    author
    content
    views
  

返回:


  "data": 
    "createPost": 
      "id": "b42ee08c-956d-4b89-afda-60fe231e86d7",
      "author": "Me",
      "content": null,
      "views": 1
    
  

mutation CreatePost 
  createPost(author: "Me", content: "content") 
    id
    author
    content
    views
  
  

返回


  "data": 
    "createPost": 
      "id": "c6af0cbf-cf05-4110-8bc2-833bf9fca9f5",
      "author": "Me",
      "content": "content",
      "views": 1
    
  

【讨论】:

以上是关于如何使用 AppSync 解析器和 Aurora 将可选字段插入为空?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 AppSync 解析器中使用多个过滤器表达式

如何使用 Appsync 中的解析器获取 dynamodb 中存在的记录总数

如何使用 Aws AppSync 将 JWT 令牌(或任何其他变量)从父解析器传递给子解析器

AppSync Dynamodb 解析器

AWS Appsync:如何创建一个解析器来检索标识符数组的详细信息?

Aws Appsync 解析器:如何创建解析器以更新列表映射 (DynaMoDB) 中的项目