本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
條件表達式
當您使用 PutItem
、 UpdateItem
和 DynamoDB 操作來變更 DeleteItem
DynamoDB 中的物件時,您可以選擇指定條件表達式,以根據在執行操作之前在 DynamoDB 中已存在的物件狀態來控制請求是否成功。
The AWS AppSync DynamoDB 解析程式允許在 PutItem
、 中指定條件表達式UpdateItem
,並DeleteItem
請求映射文件,以及如果條件失敗且未更新物件時要遵循的策略。
範例 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 解析程式會傳回變動的錯誤。不過, AWS AppSync DynamoDB 解析程式提供一些額外的功能,以協助開發人員處理一些常見的邊緣案例:
-
If 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
-
本節可讓您指定 AWS AppSync DynamoDB 解析程式在將 DynamoDB 中的目前值與預期結果進行比較後,如何處理條件檢查失敗。此區段為選用。若省略,則會預設為
Reject
策略。-
strategy
-
AWS AppSync DynamoDB 解析程式在將 DynamoDB 中的目前值與預期結果進行比較後所採用的策略。此欄位為必填,且採用下列可能值:
-
Reject
-
變動會失敗,並會將錯誤新增至 GraphQL 回應。
-
Custom
-
The AWS AppSync DynamoDB 解析程式會叫用自訂 Lambda 函數,以決定如何處理條件檢查失敗。當
strategy
設定為Custom
,lambdaArn
欄位必須包含要叫用 Lambda 函數的 ARN。
-
-
lambdaArn
-
要叫用之 Lambda 函數的 ARN,決定 AWS AppSync DynamoDB 解析程式應如何處理條件檢查失敗。只有在
strategy
設定為Custom
時,此欄位才必須指定。如需如何使用此功能的詳細資訊,請參閱處理條件檢查失敗。
-
處理條件檢查失敗
根據預設,當條件檢查失敗時, AWS AppSync DynamoDB 解析程式會傳回 DynamoDB 中物件的變動和目前值的錯誤。不過, AWS AppSync DynamoDB 解析程式提供一些額外的功能,以協助開發人員處理一些常見的邊緣案例:
-
If AWS AppSync DynamoDB 解析程式可以判斷 DynamoDB 中的目前值是否符合所需的結果,它將操作視為成功。
-
您可以設定解析程式來叫用自訂 Lambda 函數,以決定 AWS AppSync DynamoDB 解析程式應如何處理失敗,而不是傳回錯誤。
此程序的流程圖為:

檢查所需結果
當條件檢查失敗時, 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 函數來決定下一步該怎麼做。
遵循「拒絕」策略
遵循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
區段中傳回物件時,不會解析這些物件。
遵循「自訂」策略
遵循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。{ "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 } }
無法指定使用不同的操作或索引鍵。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) };