

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 條件表達式
<a name="aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions"></a>

當您使用 `PutItem`、 `UpdateItem`和 DynamoDB 操作來變更 `DeleteItem` DynamoDB 中的物件時，您可以選擇指定條件表達式，以根據在執行操作之前已在 DynamoDB 中的物件狀態來控制請求是否成功。

The AWS AppSync DynamoDB 解析程式允許在 `PutItem`、 `UpdateItem`和 `DeleteItem`請求映射文件中指定條件表達式，以及如果條件失敗且未更新物件時要遵循的策略。

## 範例 1
<a name="id19"></a>

以下 `PutItem` 映射文件沒有條件表達式。因此，即使具有相同索引鍵的項目已存在，也會將項目放入 DynamoDB，藉此覆寫現有項目。

```
{
   "version" : "2017-02-28",
   "operation" : "PutItem",
   "key" : {
      "id" : { "S" : "1" }
   }
}
```

## 範例 2
<a name="id20"></a>

下列`PutItem`映射文件確實具有條件表達式，只有在 DynamoDB 中*不存在*具有相同索引鍵的項目時，才允許操作成功。

```
{
   "version" : "2017-02-28",
   "operation" : "PutItem",
   "key" : {
      "id" : { "S" : "1" }
   },
   "condition" : {
      "expression" : "attribute_not_exists(id)"
   }
}
```

根據預設，如果條件檢查失敗， AWS AppSync DynamoDB 解析程式會傳回變動的錯誤。不過， AWS AppSync DynamoDB 解析程式提供一些額外的功能，以協助開發人員處理一些常見的邊緣案例：
+ If AWS AppSync DynamoDB 解析程式可以判斷 DynamoDB 中的目前值是否符合所需的結果，仍會將操作視為成功。
+ 您可以設定解析程式叫用自訂 Lambda 函數，以決定 AWS AppSync DynamoDB 解析程式應如何處理失敗，而不是傳回錯誤。

[處理條件檢查失敗](#aws-appsync-resolver-mapping-template-reference-dynamodb-condition-handling)一節將更詳細地說明這些內容。

如需 DynamoDB 條件表達式的詳細資訊，請參閱 [DynamoDB ConditionExpressions 文件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html)。

## 指定條件
<a name="aws-appsync-resolver-mapping-template-reference-dynamodb-condition-specification"></a>

`PutItem`、`UpdateItem` 和 `DeleteItem` 要求映射文件都允許可指定選用的 `condition` 區段。若省略，則不會有條件檢查。若指定，條件必須為 true，操作才會成功。

`condition` 區段的結構如下：

```
"condition" : {
    "expression" : "someExpression"
    "expressionNames" : {
        "#foo" : "foo"
    },
    "expressionValues" : {
        ":bar" : ... typed value
    },
    "equalsIgnore" : [ "version" ],
    "consistentRead" : true,
    "conditionalCheckFailedHandler" : {
        "strategy" : "Custom",
        "lambdaArn" : "arn:..."
    }
}
```

下列欄位指定條件：

** `expression` **  
更新表達式本身。如需如何編寫條件表達式的詳細資訊，請參閱 [DynamoDB ConditionExpressions 文件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html)。必須指定此欄位。

** `expressionNames` **  
表達式屬性名稱預留位置的替代，形式為索引鍵值對。索引鍵對應至*表達*式中使用的名稱預留位置，且值必須是對應於 DynamoDB 中項目屬性名稱的字串。此欄位為選用的，應只能填入於*表達式*中所用表達式屬性名稱預留位置的替代。

** `expressionValues` **  
表達式屬性值預留位置的替代，形式為索引值對。鍵對應用於表達式的值預留位置，值必須是類型值。如需如何指定「類型值」的詳細資訊，請參閱[類型系統 (請求映射)](aws-appsync-resolver-mapping-template-reference-dynamodb-typed-values-request.md)。此必須指定。此欄位為選用的，應只能填入用於表達式中表達式屬性值預留位置的替代。

其餘欄位會告知 AWS AppSync DynamoDB 解析程式如何處理條件檢查失敗：

** `equalsIgnore` **  
當條件檢查在使用 `PutItem`操作時失敗時， AWS AppSync DynamoDB 解析程式會將目前在 DynamoDB 中的項目與嘗試寫入的項目進行比較。如果兩者相同，則操作視為成功。您可以使用 `equalsIgnore` 欄位來指定執行該比較時 AWS AppSync 應忽略的屬性清單。例如，如果唯一的差異是`version`屬性，它會將操作視為成功。此欄位為選用欄位。

** `consistentRead` **  
當條件檢查失敗時， AWS AppSync 會使用強式一致讀取，從 DynamoDB 取得項目的目前值。您可以使用此欄位，指示 AWS AppSync DynamoDB 解析程式改用最終一致讀取。此欄位為選用，預設值為 `true`。

** `conditionalCheckFailedHandler` **  
本節可讓您指定 AWS AppSync DynamoDB 解析程式在將 DynamoDB 中的目前值與預期結果進行比較後，如何處理條件檢查失敗。此區段為選用。若省略，則會預設為 `Reject` 策略。    
** `strategy` **  
在將 DynamoDB 中的目前值與預期結果進行比較後， AWS AppSync DynamoDB 解析程式採取的策略。此欄位為必填，且採用下列可能值：    
** `Reject` **  
變動會失敗，並會將錯誤新增至 GraphQL 回應。  
** `Custom` **  
The AWS AppSync DynamoDB 解析程式會叫用自訂 Lambda 函數，以決定如何處理條件檢查失敗。當 `strategy` 設定為 `Custom`，`lambdaArn` 欄位必須包含要叫用 Lambda 函數的 ARN。  
** `lambdaArn` **  
要叫用的 Lambda 函數 ARN，決定 AWS AppSync DynamoDB 解析程式應如何處理條件檢查失敗。只有在 `strategy` 設定為 `Custom` 時，此欄位才必須指定。如需如何使用此功能的詳細資訊，請參閱[處理條件檢查失敗](#aws-appsync-resolver-mapping-template-reference-dynamodb-condition-handling)。

## 處理條件檢查失敗
<a name="aws-appsync-resolver-mapping-template-reference-dynamodb-condition-handling"></a>

根據預設，當條件檢查失敗時， AWS AppSync DynamoDB 解析程式會傳回變動的錯誤，以及 DynamoDB 中物件的目前值。不過， AWS AppSync DynamoDB 解析程式提供一些額外的功能，以協助開發人員處理一些常見的邊緣案例：
+ If AWS AppSync DynamoDB 解析程式可以判斷 DynamoDB 中的目前值是否符合所需的結果，仍會將操作視為成功。
+ 您可以設定解析程式叫用自訂 Lambda 函數，以決定 AWS AppSync DynamoDB 解析程式應如何處理失敗，而不是傳回錯誤。

此程序的流程圖為：

![\[Flowchart showing process for transforming requests with mutation attempts and value checks.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/DynamoDB-condition-check-failure-handling.png)


### 檢查所需結果
<a name="checking-for-the-desired-result"></a>

當條件檢查失敗時， AWS AppSync DynamoDB 解析程式會執行 `GetItem` DynamoDB 請求，從 DynamoDB 取得項目的目前值。在預設情況下，它會使用強式一致性讀取，但這可使用 `condition` 區塊中的 `consistentRead` 欄位來設定，並和預期結果進行比較：
+ 對於 `PutItem`操作， AWS AppSync DynamoDB 解析程式會將目前的值與其嘗試寫入的值進行比較，但不包括`equalsIgnore`比較中列出的任何屬性。如果項目相同，它會將操作視為成功，並傳回從 DynamoDB 擷取的項目。否則，其將按照設定的策略。

  例如，如果 `PutItem` 要求映射文件外觀如下：

  ```
  {
     "version" : "2017-02-28",
     "operation" : "PutItem",
     "key" : {
        "id" : { "S" : "1" }
     },
     "attributeValues" : {
        "name" : { "S" : "Steve" },
        "version" : { "N" : 2 }
     },
     "condition" : {
        "expression" : "version = :expectedVersion",
        "expressionValues" : {
            ":expectedVersion" : { "N" : 1 }
        },
        "equalsIgnore": [ "version" ]
     }
  }
  ```

  而目前在 DynamoDB 中的項目外觀如下：

  ```
  {
     "id" : { "S" : "1" },
     "name" : { "S" : "Steve" },
     "version" : { "N" : 8 }
  }
  ```

  The AWS AppSync DynamoDB 解析程式會將嘗試寫入的項目與目前值進行比較，查看唯一的差異是 `version` 欄位，但因為它設定為忽略 `version` 欄位，它會將操作視為成功，並傳回從 DynamoDB 擷取的項目。
+ 對於 `DeleteItem`操作， AWS AppSync DynamoDB 解析程式會檢查以確認項目已從 DynamoDB 傳回。如果沒有項目傳回，則操作視為成功。否則，其將按照設定的策略。
+ 對於 `UpdateItem`操作， AWS AppSync DynamoDB 解析程式沒有足夠的資訊來判斷目前在 DynamoDB 中的項目是否符合預期結果，因此遵循設定的策略。

如果 DynamoDB 中物件的目前狀態與預期結果不同， AWS AppSync DynamoDB 解析程式會遵循設定的策略，以拒絕變動或叫用 Lambda 函數來決定接下來要做什麼。

### 遵循「拒絕」策略
<a name="following-the-reject-strategy"></a>

遵循 `Reject`策略時， AWS AppSync DynamoDB 解析程式會傳回變動的錯誤。

例如，假設變動要求如下：

```
mutation {
    updatePerson(id: 1, name: "Steve", expectedVersion: 1) {
        Name
        theVersion
    }
}
```

如果從 DynamoDB 傳回的項目如下所示：

```
{
   "id" : { "S" : "1" },
   "name" : { "S" : "Steve" },
   "version" : { "N" : 8 }
}
```

而回應映射範本如下所示：

```
{
   "id" : $util.toJson($context.result.id),
   "Name" : $util.toJson($context.result.name),
   "theVersion" : $util.toJson($context.result.version)
}
```

GraphQL 回應的外觀如下所示：

```
{
  "data": null,
  "errors": [
    {
      "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)"
      "errorType": "DynamoDB:ConditionalCheckFailedException",
      ...
    }
  ]
}
```

此外，如果傳回物件中的任何欄位皆由其他解析程式填入，且變動成功，則在 `error` 區段中傳回物件時，不會解析這些物件。

### 遵循「自訂」策略
<a name="following-the-custom-strategy"></a>

遵循`Custom`策略時， AWS AppSync DynamoDB 解析程式會叫用 Lambda 函數來決定接下來要做什麼。Lambda 函數會選擇下列其中一個選項：
+  `reject` 變動。這可讓 AWS AppSync DynamoDB 解析程式的行為如同設定的策略為 `Reject`，傳回 DynamoDB 中物件的變動錯誤和目前值，如上一節所述。
+  `discard` 變動。這可讓 AWS AppSync DynamoDB 解析程式無提示地忽略條件檢查失敗，並在 DynamoDB 中傳回 值。
+  `retry` 變動。這會通知 AWS AppSync DynamoDB 解析程式使用新的請求映射文件重試變動。

 **Lambda 叫用要求** 

The AWS AppSync DynamoDB 解析程式會叫用 中指定的 Lambda 函數`lambdaArn`。它會使用資料來源上所設定的相同 `service-role-arn`。叫用承載的結構如下：

```
{
    "arguments": { ... },
    "requestMapping": {... },
    "currentValue": { ... },
    "resolver": { ... },
    "identity": { ... }
}
```

欄位定義如下：

** `arguments` **  
來自 GraphQL 變動的引數。這與可在 `$context.arguments` 中要求映射文件取得的引數相同。

** `requestMapping` **  
此操作的要求映射文件。

** `currentValue` **  
DynamoDB 中物件的目前值。

** `resolver` **  
有關 AWS AppSync 解析程式的資訊。

** `identity` **  
發起人的相關資訊。這與可在 `$context.identity` 中要求映射文件取得的身分資訊相同。

承載的完整範例：

```
{
    "arguments": {
        "id": "1",
        "name": "Steve",
        "expectedVersion": 1
    },
    "requestMapping": {
        "version" : "2017-02-28",
        "operation" : "PutItem",
        "key" : {
           "id" : { "S" : "1" }
        },
        "attributeValues" : {
           "name" : { "S" : "Steve" },
           "version" : { "N" : 2 }
        },
        "condition" : {
           "expression" : "version = :expectedVersion",
           "expressionValues" : {
               ":expectedVersion" : { "N" : 1 }
           },
           "equalsIgnore": [ "version" ]
        }
    },
    "currentValue": {
        "id" : { "S" : "1" },
        "name" : { "S" : "Steve" },
        "version" : { "N" : 8 }
    },
    "resolver": {
        "tableName": "People",
        "awsRegion": "us-west-2",
        "parentType": "Mutation",
        "field": "updatePerson",
        "outputType": "Person"
    },
    "identity": {
        "accountId": "123456789012",
        "sourceIp": "x.x.x.x",
        "user": "AIDAAAAAAAAAAAAAAAAAA",
        "userArn": "arn:aws:iam::123456789012:user/appsync"
    }
}
```

 **Lambda 叫用回應** 

Lambda 函數可以檢查調用承載並套用任何商業邏輯，以決定 AWS AppSync DynamoDB 解析程式應如何處理失敗。處理條件檢查失敗有三個選項：
+  `reject` 變動。此選項的回應承載必須具有此架構：

  ```
  {
      "action": "reject"
  }
  ```

  這可讓 AWS AppSync DynamoDB 解析程式的行為如同設定的策略為 `Reject`，傳回 DynamoDB 中物件的變動錯誤和目前值，如上節所述。
+  `discard` 變動。此選項的回應承載必須具有此架構：

  ```
  {
      "action": "discard"
  }
  ```

  這會通知 AWS AppSync DynamoDB 解析程式以無提示方式忽略條件檢查失敗，並在 DynamoDB 中傳回 值。
+  `retry` 變動。此選項的回應承載必須具有此架構：

  ```
  {
      "action": "retry",
      "retryMapping": { ... }
  }
  ```

  這會通知 AWS AppSync DynamoDB 解析程式使用新的請求映射文件重試變動。`retryMapping` 區段的結構取決於 DynamoDB 操作，並且是該操作完整請求映射文件的子集。

  若是 `PutItem`，`retryMapping` 區段的結構如下。如需 `attributeValues` 欄位的描述，請參閱 [PutItem](aws-appsync-resolver-mapping-template-reference-dynamodb-putitem.md)。

  ```
  {
      "attributeValues": { ... },
      "condition": {
          "equalsIgnore" = [ ... ],
          "consistentRead" = true
      }
  }
  ```

  若是 `UpdateItem`，`retryMapping` 區段的結構如下。如需 `update` 區段的描述，請參閱 [UpdateItem](aws-appsync-resolver-mapping-template-reference-dynamodb-updateitem.md)。

  ```
  {
      "update" : {
          "expression" : "someExpression"
          "expressionNames" : {
              "#foo" : "foo"
          },
          "expressionValues" : {
              ":bar" : ... typed value
          }
      },
      "condition": {
          "consistentRead" = true
      }
  }
  ```

  若是 `DeleteItem`，`retryMapping` 區段的結構如下。

  ```
  {
      "condition": {
          "consistentRead" = true
      }
  }
  ```

  無法指定使用不同的操作或索引鍵。The AWS AppSync DynamoDB 解析程式僅允許對相同物件重試相同的操作。此外，`condition` 區段不允許指定 `conditionalCheckFailedHandler`。如果重試失敗， AWS AppSync DynamoDB 解析程式會遵循 `Reject`策略。

此為 Lambda 函數處理失敗 `PutItem` 要求的範例。商業邏輯的重點是發起人為何。如果是由 提出`jeffTheAdmin`，它會重試請求，`expectedVersion`從目前在 DynamoDB 中的項目更新 `version`和 。否則，它會拒絕變動。

```
exports.handler = (event, context, callback) => {
    console.log("Event: "+ JSON.stringify(event));

    // Business logic goes here.

    var response;
    if ( event.identity.user == "jeffTheAdmin" ) {
        response = {
            "action" : "retry",
            "retryMapping" : {
                "attributeValues" : event.requestMapping.attributeValues,
                "condition" : {
                    "expression" : event.requestMapping.condition.expression,
                    "expressionValues" : event.requestMapping.condition.expressionValues
                }
            }
        }
        response.retryMapping.attributeValues.version = { "N" : event.currentValue.version.N + 1 }
        response.retryMapping.condition.expressionValues[':expectedVersion'] = event.currentValue.version

    } else {
        response = { "action" : "reject" }
    }

    console.log("Response: "+ JSON.stringify(response))
    callback(null, response)
};
```