本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
條件表達式
當您使用PutItem
、UpdateItem
和 DeleteItem
DynamoDB 作業在 DynamoDB 中變更物件時,您可以選擇性地指定條件運算式,以根據執行作業前已在 DynamoDB 中的物件狀態控制請求是否成功。
AWS AppSync DynamoDB 解析器允許在、和DeleteItem
請求對應文件中指定條件運算式 PutItem
UpdateItem
,以及在條件失敗且物件未更新時應遵循的策略。
範例 1
以下 PutItem
映射文件沒有條件表達式。因此,即使已存在具有相同金鑰的項目,它也會將項目置於 DynamoDB 中,進而覆寫現有項目。
{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } } }
範例 2
下列PutItem
對應文件具有條件運算式,只有在 DynamoDB 中不存在具有相同索引鍵的項目時,才允許作業成功。
{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "condition" : { "expression" : "attribute_not_exists(id)" } }
依預設,如果條件檢查失敗, AWS AppSync DynamoDB 解析器會針對 GraphQL 回應區段中的data
欄位中的突變和 DynamoDB 中物件的目前值傳回錯誤。error
不過, AWS AppSync DynamoDB 解析器提供一些額外的功能,可協助開發人員處理一些常見的邊緣案例:
-
如果 AWS AppSync DynamoDB 解析器可以判斷 DynamoDB 中的目前值是否符合所需的結果,它會將作業視為無論如何都成功。
-
您可以將解析器設定為叫用自訂 Lambda 函數,以決定 AWS AppSync DynamoDB 解析器應如何處理失敗,而不會傳回錯誤。
處理條件檢查失敗一節將更詳細地說明這些內容。
如需有關 DynamoDB 條件運算式的詳細資訊,請參閱 DynamoDB ConditionExpressions 文件。
指定條件
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 文件。必須指定此欄位。
-
expressionNames
-
表達式屬性名稱預留位置的替代,形式為索引鍵值對。索引鍵對應至運算式中使用的名稱預留位置,而且值必須是對應至 DynamoDB 中項目的屬性名稱的字串。此欄位為選用的,應只能填入於表達式中所用表達式屬性名稱預留位置的替代。
-
expressionValues
-
表達式屬性值預留位置的替代,形式為索引值對。鍵對應用於表達式的值預留位置,值必須是類型值。如需如何指定「類型值」的詳細資訊,請參閱類型系統 (請求映射)。此必須指定。此欄位為選用的,應只能填入用於表達式中表達式屬性值預留位置的替代。
其餘欄位會告訴 AWS AppSync DynamoDB 解析程式如何處理條件檢查失敗:
-
equalsIgnore
-
使用
PutItem
作業時,如果條件檢查失敗, AWS AppSync DynamoDB 解析器會將目前在 DynamoDB 中的項目與嘗試寫入的項目進行比較。如果兩者相同,則操作視為成功。您可以使用equalsIgnore
欄位來指定執行該比較時 AWS AppSync 應忽略的屬性清單。例如,如果唯一的區別是version
屬性,它會將作業視為成功。此欄位為選用欄位。 -
consistentRead
-
當條件檢查失敗時, AWS AppSync 會使用強烈一致讀取從 DynamoDB 取得項目的目前值。您可以使用此欄位告知 AWS AppSync DynamoDB 解析器改用最終一致性讀取。此欄位為選用,預設值為
true
。 -
conditionalCheckFailedHandler
-
本節可讓您指定 DynamoDB 解析器在將 AWS AppSync DynamoDB 中的目前值與預期結果進行比較後,如何處理條件檢查失敗。此區段為選用。若省略,則會預設為
Reject
策略。-
strategy
-
DynamoDB 解析程式在將 AWS AppSync DynamoDB 中的目前值與預期結果進行比較之後所採用的策略。此欄位為必填,且採用下列可能值:
-
Reject
-
突變失敗,並且 GraphQL 回應
error
區段中某個data
欄位中 DynamoDB 中物件的突變和目前值出現錯誤。 -
Custom
-
AWS AppSync DynamoDB 解析器會叫用自訂 Lambda 函數來決定如何處理條件檢查失敗。當設定
strategy
為時Custom
,lambdaArn
欄位必須包含要叫用ARN的 Lambda 函數。
-
-
lambdaArn
-
要叫用ARN的 Lambda 函數,可決定 AWS AppSync DynamoDB 解析程式應如何處理條件檢查失敗。只有在
strategy
設定為Custom
時,此欄位才必須指定。如需如何使用此功能的詳細資訊,請參閱處理條件檢查失敗。
-
處理條件檢查失敗
依預設,當條件檢查失敗時, AWS AppSync DynamoDB 解析器會針對 GraphQL 回應區段中的data
欄位中的突變和 DynamoDB 中物件的目前值傳回錯誤。error
不過, AWS AppSync DynamoDB 解析器提供一些額外的功能,可協助開發人員處理一些常見的邊緣案例:
-
如果 AWS AppSync DynamoDB 解析器可以判斷 DynamoDB 中的目前值是否符合所需的結果,它會將作業視為無論如何都成功。
-
您可以將解析器設定為叫用自訂 Lambda 函數,以決定 AWS AppSync DynamoDB 解析器應如何處理失敗,而不會傳回錯誤。
此程序的流程圖為:
![](images/DynamoDB-condition-check-failure-handling.png)
檢查所需的結果
當條件檢查失敗時, AWS AppSync DynamoDB 解析器會執行 DynamoDB 請求,以從 GetItem
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 } }
AWS AppSync DynamoDB 解析器會將嘗試寫入的項目與目前值進行比較,請參閱唯一的區別是
version
欄位,但由於設定為忽略欄version
位,因此會將作業視為成功,並傳回從 DynamoDB 擷取的項目。 -
針對此
DeleteItem
作業, AWS AppSync DynamoDB 解析程式會檢查以確認是否已從 DynamoDB 傳回項目。如果沒有項目傳回,則操作視為成功。否則,其將按照設定的策略。 -
針對此
UpdateItem
作業, AWS AppSync DynamoDB 解析器沒有足夠的資訊來判斷 DynamoDB 中目前的項目是否符合預期的結果,因此遵循設定的策略。
如果 DynamoDB 中物件的目前狀態與預期結果不同, AWS AppSync DynamoDB 解析器會遵循設定的策略,以拒絕突變或叫用 Lambda 函數來決定下一步要執行的動作。
遵循「拒絕」策略
遵循Reject
策略時, AWS AppSync DynamoDB 解析器會針對突變傳回錯誤,而 DynamoDB 中物件的目前值也會傳回 GraphQL 回應區段中的data
欄位中。error
從 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", "data": { "Name": "Steve", "theVersion": 8 }, ... } ] }
此外,如果傳回物件中的任何欄位皆由其他解析程式填入,且變動成功,則在 error
區段中傳回物件時,不會解析這些物件。
遵循「自定義」策略
遵循Custom
策略時, AWS AppSync DynamoDB 解析程式會叫用 Lambda 函數來決定下一步該做什麼。Lambda 函數會選擇下列其中一個選項:
-
reject
變動。這會告訴 AWS AppSync DynamoDB 解析器的行為如同已設定策略一樣Reject
,傳回 DynamoDB 中物件的突變錯誤和目前值,如上一節所述。 -
discard
變動。這會告知 AWS AppSync DynamoDB 解析程式以無訊息方式忽略條件檢查失敗,並傳回 DynamoDB 中的值。 -
retry
變動。這會告訴 AWS AppSync DynamoDB 解析器使用新的請求對應文件重試突變。
Lambda 叫用要求
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。{ "attributeValues": { ... }, "condition": { "equalsIgnore" = [ ... ], "consistentRead" = true } }
若是
UpdateItem
,retryMapping
區段的結構如下。如需update
區段的描述,請參閱UpdateItem。{ "update" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value } }, "condition": { "consistentRead" = true } }
若是
DeleteItem
,retryMapping
區段的結構如下。{ "condition": { "consistentRead" = true } }
無法指定使用不同的操作或索引鍵。 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) };