Amplify + AppSync 不改变对象

Posted

技术标签:

【中文标题】Amplify + AppSync 不改变对象【英文标题】:Amplify + AppSync not mutating object 【发布时间】:2020-01-07 16:45:32 【问题描述】:

我试图在没有任何先验知识的情况下使用 Amplify + AppSync/GraphQL 设置应用程序,但现在我面临很多问题,以至于我怀疑这是一个好的决定。

我已经通过 Amplify 添加了一个 AppSync API

查询目前工作正常,但是,我很难使突变工作,更糟糕的是,它们没有给我任何错误。

我的数据库架构的重要部分如下:

type Mutation 
    updateVideoOnDemand(input: UpdateVideoOnDemandInput!): VideoOnDemand


type ScriptRow 
    loop: Int
    timeStart: Int
    character: String
    text: String
    guessed: Boolean


input ScriptRowInput 
    loop: Int
    timeStart: Int
    character: String
    text: String
    guessed: Boolean


input UpdateVideoOnDemandInput 
    guid: String!
    thumbNailUrl: [String]
    startTime: String
    workflowStatus: String
    srcVideo: String
    hlsUrl: String
    dashUrl: String
    scriptUrl: String
    mp4Urls: [String]
    transcriptUri: String
    isLoadingLoops: Boolean
    documentKey: String
    initialOffset: Int
    videoOffset: Int
    scriptRows: [ScriptRowInput!]


type VideoOnDemand 
    guid: String!
    thumbNailUrl: [String]
    startTime: String
    workflowStatus: String
    srcVideo: String
    hlsUrl: String
    dashUrl: String
    scriptUrl: String
    mp4Urls: [String]
    transcriptUri: String
    isLoadingLoops: Boolean
    documentKey: String
    initialOffset: Int
    videoOffset: Int
    scriptRows: [ScriptRow]

然后,我使用 Amplify codegen 工具生成了本地代码 哪个看起来不错

export const updateVideoOnDemand = `mutation UpdateVideoOnDemand($input: UpdateVideoOnDemandInput!) 
  updateVideoOnDemand(input: $input) 
    guid
    thumbNailUrl
    startTime
    workflowStatus
    srcVideo
    hlsUrl
    dashUrl
    scriptUrl
    mp4Urls
    transcriptUri
    isLoadingLoops
    documentKey
    initialOffset
    videoOffset
    scriptRows 
      loop
      timeStart
      character
      text
      guessed
    
  

`;

首先我尝试使用简单的 AWS API.GraphQL

        API.graphql(graphqlOperation(mutations.updateVideoOnDemand, 
          input: 
            guid: video.guid,
            initialOffset: values.initial_offset,
            videoOffset: values.video_offset,
            workflowStatus: 'Test',
            isLoadingLoops: true,
            scriptRows: rows,
          
        )).then(
          updatedVideo => 
            message.success('Saved');
          
        ).catch(err => message.error('Error saving data: ' + err))

突变的映射解析器:


  "version": "2017-02-28",
  "operation": "UpdateItem",
  "key": 
    "guid": $util.dynamodb.toDynamoDBJson($ctx.args.input.guid),
  ,

  ## Set up some space to keep track of things we're updating **
  #set( $expNames  =  )
  #set( $expValues =  )
  #set( $expSet =  )
  #set( $expAdd =  )
  #set( $expRemove = [] )

  ## Iterate through each argument, skipping keys **
  #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args.input, ["guid"]).entrySet() )
    #if( $util.isNull($entry.value) )
      ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **

      #set( $discard = $expRemove.add("#$entry.key") )
      $!expNames.put("#$entry.key", "$entry.key")
    #else
      ## Otherwise set (or update) the attribute on the item in DynamoDB **

      $!expSet.put("#$entry.key", ":$entry.key")
      $!expNames.put("#$entry.key", "$entry.key")
      $!expValues.put(":$entry.key", $util.dynamodb.toDynamoDB($entry.value))
    #end
  #end

  ## Start building the update expression, starting with attributes we're going to SET **
  #set( $expression = "" )
  #if( !$expSet.isEmpty() )
    #set( $expression = "SET" )
    #foreach( $entry in $expSet.entrySet() )
      #set( $expression = "$expression $entry.key = $entry.value" )
      #if ( $foreach.hasNext )
        #set( $expression = "$expression," )
      #end
    #end
  #end

  ## Continue building the update expression, adding attributes we're going to ADD **
  #if( !$expAdd.isEmpty() )
    #set( $expression = "$expression ADD" )
    #foreach( $entry in $expAdd.entrySet() )
      #set( $expression = "$expression $entry.key $entry.value" )
      #if ( $foreach.hasNext )
        #set( $expression = "$expression," )
      #end
    #end
  #end

  ## Continue building the update expression, adding attributes we're going to REMOVE **
  #if( !$expRemove.isEmpty() )
    #set( $expression = "$expression REMOVE" )

    #foreach( $entry in $expRemove )
      #set( $expression = "$expression $entry" )
      #if ( $foreach.hasNext )
        #set( $expression = "$expression," )
      #end
    #end
  #end

  ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
  "update": 
    "expression": "$expression",
    #if( !$expNames.isEmpty() )
      "expressionNames": $utils.toJson($expNames),
    #end
    #if( !$expValues.isEmpty() )
      "expressionValues": $utils.toJson($expValues),
    #end
  ,

  "condition": 
    "expression": "attribute_exists(#guid)",
    "expressionNames": 
      "#guid": "guid",
    ,
  

响应映射模板:

$util.toJson($context.result)

该命令似乎运行成功,我得到了更新的视频,我可以看到更新的数据......但是数据库端的某些字段没有更新......在这种情况下,字段@ 987654326@ 和 scriptRows 没有更新......如果我重新加载页面,我会再次获得旧结果,如果我直接检查 DynamoDB 实例,我还会看到前 3 个项目已更新,但其余部分没有更新。

我已尝试迁移代码以使用 AWSAppSync Client/Apollo.... 错误仍然存​​在。

知道是什么原因造成的吗?

更新

有一件事我不确定它们是否可能表明有问题:

当我转到 AppSync 控制台 -> 查询,然后单击“播放”图标时,我只看到 2 个选项可供选择:createVideoOnDemandlistVideoOnDemand,我在那里没有看到更新,这可能表明存在问题?

【问题讨论】:

你能分享 API 上那个突变的映射模板吗? ``` ``` 变异帮助 updateVideoOnDemand(input: guid: "2", initialOffset: 1, videoOffset:2, workflowStatus: "Test", isLoadingLoops: true, scriptRows: [ loop: 1 timeStart: 2 character: "test" text: "test" 猜测: false ]) guid isLoadingLoops initialOffset videoOffset workflowStatus scriptRows loop timeStart character text ``` @danielfranca 更新突变是否显示在控制台的文档部分?单击“播放”图标时显示的选项取决于您在控制台编辑器中编写的查询,因此这不一定表明存在问题。但是,如果文档部分中没有它,则意味着您尚未将最新的架构 + 解析器推送到云端。如果您想将您的放大项目发布到 GitHub,我可以帮助您进一步排除故障,并在我们解决此问题后返回此处。 在这种情况下,有一个 DynamoDB 触发器正在覆盖表上的更改。 我遇到了这个。在无法从 Lambda 或 Angular 更新后,我通过 AppSync 直接触发了突变。 updateAsset(input: id: "b34d3aa3-fbc4-48b5-acba-af616001630f", description: "AppSync" 并且它不会更改描述字段。我可以设置新字段,但无法编辑现有字段。在这一点上我一无所知。 【参考方案1】:

看起来这与应用同步/放大解决冲突的方式有关。如果启用了 DataStore,则冲突解决处于活动状态。

当您在服务器端使用来自 NodeJS 的 GraphQL 以及在客户端使用 DataStore 客户端(例如带有 IAM 身份验证的 lambda)时,您可能需要此信息:https://docs.amplify.aws/lib/graphqlapi/graphql-from-nodejs/q/platform/js

包括 _version 数字有效。有道理。

另请参阅: https://github.com/aws-amplify/amplify-cli/issues/3237(更新突变 GraphQL 以使新创建的模型不起作用),请参阅评论:https://github.com/aws-amplify/amplify-cli/issues/3237#issuecomment-584375936

无效示例:

工作示例:

请注意:

https://docs.amplify.aws/lib/datastore/how-it-works/q/platform/js#writing-data-from-the-appsync-console

从 AppSync 控制台写入数据

DataStore 主要是为开发人员设计的,无需专注于 后端并让您的应用程序代码和工作流程创建 一切。但是,在某些用例中,您将使用 AppSync 控制台、Lambda 函数或其他带外进程 写入数据(例如批处理操作或数据迁移),您可能 在没有 DataStore 客户端的情况下发送 GraphQL 操作。

在这些情况下,重要的是 GraphQL 的选择集 突变包括模型的所有必需字段,包括: _lastChangedAt、_version 和 _deleted,以便 DataStore 客户端可以对这些更新做出反应。您还需要发送当前 变异输入参数中的对象版本为 _version 以便 服务可以相应地采取行动。如果您不发送此信息 在全局同步过程中,客户端最终仍会赶上, 但您不会看到客户端 DataStore 的实时更新 存储库。

突变示例:

mutation UpdatePost 
  updatePost(input: 
    id: "12345"
    title: "updated title 19:40"
    status: ACTIVE
    rating: 5
    _version: 7
  ) 
    id
    title
    status
    rating
    _lastChangedAt
    _version
    _deleted
  

【讨论】:

以上是关于Amplify + AppSync 不改变对象的主要内容,如果未能解决你的问题,请参考以下文章

AWS Amplify Appsync 在创建具有关系的对象时解决错误

aws amplify appsync 中的 Graphql 突变错误

将现有 AppSync API 与/ Amplify 一起使用

AWS Amplify AppSync 订阅无法正常工作

“没有当前用户”:是不是甚至可以通过 Amplify 使用身份验证类型 AMAZON_COGNITO_USER_POOLS 对 AWS AppSync 进行未经身份验证的调用?

使用 AWS Amplify/AppSync 的嵌套 GraphQL 突变