发布 AWS Amplify GraphQL 突变时如何避免在数组中创建重复项

Posted

技术标签:

【中文标题】发布 AWS Amplify GraphQL 突变时如何避免在数组中创建重复项【英文标题】:How to avoid creating duplicate items in an array when posting an AWS Amplify GraphQL mutation 【发布时间】:2020-11-27 23:45:03 【问题描述】:

前言:我是 GraphQL 和 Amplify 的新手。

我有一个包含两个数组的用户对象,一个名为preferred_genres,另一个名为preferred_characters。我有一个个人资料页面,用户可以在其中编辑他们的个人资料并将项目添加到这些数组中。

AWS Amplify 提供的更新突变似乎只是将元素添加到数组中,而不会删除它们。如果在我的 UI 上我从列表中删除一个项目,然后提交更新突变,则该项目不会从我的后端中删除。如果我将一个项目添加到数组中,该项目将添加到后端,但我最终也会得到那些已经在后端的重复值。

我想要做的是用我从前端提交的数据覆盖后端的数组。我错过了一些明显的东西吗?在 GraphQL 中是否有更合适的方法来实现这一点?

架构

type User @model 
  id: ID!
  ...
  preferred_characters: [Character]
  preferred_genres: [Genre]
  ...

【问题讨论】:

【参考方案1】:

DataStore 的冲突解决文档:

更新冲突解决方案:

    一种方法是按照documentation 的建议更新它(我这样做的方式)。

    我检查了哪些文件发生了变化,唯一重要的更新密钥可以在amplify/backend/api/<yourApi>/transform.conf.json中找到

发件人:

收件人:

【讨论】:

通过上述方法,我的项目目前没有被复制。我正在密切关注它。如果重复出现,我会更新答案。【参考方案2】:

我偶然发现了 this question in the Amplify GitHub issues 关于 AWSJSON 标量有类似问题的信息。该问题似乎与 API 中的 conflict resolution 有关。

我不记得设置了,但我尝试了 amplify update API,选择了我的 GraphQL API 和高级选项,拒绝任何冲突解决并运行 amplify push

现在值按预期保存。当我从数组中删除一个项目时,它会从后端删除,反之亦然。

【讨论】:

您是如何禁用冲突解决的?在 CLI 中,我看到的只是不配置冲突解决的选项,但这听起来不像是禁用它。 这是几个月前的事了,所以我记不清了。备份您的放大配置并尝试不配置冲突解决选项并放大推送。如果它没有帮助,那么您可以恢复到以前的配置。【参考方案3】:

实现这一点的一种方法是更改​​您的 updateUser 解析器以更新或创建这些条目。


    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : 
        "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
    ,

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

    ## Increment "version" by 1 **
    $!expAdd.put("version", ":one")
    $!expValues.put(":one",  "N" : 1 )

    ## Iterate through each argument, skipping "id" and "expectedVersion" **
    #foreach( $entry in $context.arguments.entrySet() )
        #if( $entry.key != "id" && $entry.key != "expectedVersion" )
            #if( (!$entry.value) && ("$!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",  "S" : "$entry.value" )
            #end
        #end
    #end

    ## Start building the update expression, starting with attributes you'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 you'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 you'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"       : "version = :expectedVersion",
        "expressionValues" : 
            ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
        
    

More details

【讨论】:

感谢您的回复。我对这个看似简单的要求有多少间接性感到非常震惊:更新用户对象上的数组。我知道 Amplify 会为您生成大量代码,但成本是多少?为了进行最简单的更改,您需要学习编写 Apache Velocity 模板语言模板吗?只看他们文档中的示例就让我头晕目眩。 宣讲它@Roy。我现在几乎遇到了这个确切的问题,我已经等了好几个星期才让有人回答我的问题。 同样的,面临同样的问题,仍然找不到直接的解决方案

以上是关于发布 AWS Amplify GraphQL 突变时如何避免在数组中创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

发布 AWS Amplify GraphQL 突变时如何避免在数组中创建重复项

AWS Amplify + Graphql + Dynamodb:突变时出现 ConditionalCheckFailedException 错误

在反应本机应用程序中使用 AWS Amplify 在 GraphQL 突变中出错

AWS Amplify CLI 生成的 GraphQL 突变中的 $condition 输入参数是啥?

使用 AWS Amplify Auth 和 GraphQL API,您将如何进行一些公共和一些私有查询/突变调用?

我可以使用 aws amplify 和 @auth 装饰器将 GraphQL 突变设为私有吗?这被认为是一种安全的方法吗?