graphql - Amplify + AppSync 不会改变对象

标签 graphql apollo react-apollo aws-amplify aws-appsync

我尝试使用 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)

该命令似乎运行成功,我得到了更新的视频作为结果,并且我可以看到其上更新的数据...但是某些字段未在数据库端更新...在本例中字段 isLoadingLoopsscriptRows 未更新...如果我重新加载页面,我会再次得到旧结果,如果我直接检查 DynamoDB 实例,我还会看到前 3 个项目已更新,但其余部分未更新。

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

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

更新

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

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

最佳答案

看起来这与应用程序同步/放大解决冲突的方式有关。如果启用了 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

不工作示例: enter image description here

工作示例: enter image description here

请注意:

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

Writing data from the AppSync console

DataStore is designed primarily for developers to not have to focus on the backend and let your application code and workflow create everything. However, there will be some use cases where you will use the AppSync console, a Lambda function, or other out of band processes to write data (such as batch actions or data migrations) and you might send GraphQL operations without the DataStore client.

In these cases it’s important that the selection set of your GraphQL mutation includes all the required fields of the model, including: _lastChangedAt, _version, and _deleted so that the DataStore clients can react to these updates. You will also need to send the current object version in the mutation input argument as _version so that the service can act accordingly. If you do not send this information the clients will still eventually catch up during the global sync process, but you will not see realtime updates to the client DataStore repositories.

突变示例:

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

关于graphql - Amplify + AppSync 不会改变对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57794338/

相关文章:

graphql - 使用 GraphQL 突变时是否可以不返回任何数据?

javascript - 为javascript添加/删除文本多行

reactjs - 突变后重新获取查询不起作用

Graphql 包含指令

javascript - 如何从 graphql 模式中获取所有类型的列表?

c# - 在 C# 中与 Hotchocolate GraphQL 和 TestServer 进行集成测试

java - 如何使用 Apollo graphql 动态调整查询形状(字段)?

graphql - 在 Apollo Server 中调用另一个解析器的最佳方法是什么?

Apollo GraphQL Fetch更多

reactjs - TypeError - undefined 不是一个对象(评估 'c.currentObservable.query.refetch' )。在 native react 中