#javascript #python #typescript #amazon-web-services #amazon-dynamodb
#amazon-web-services #лямбда #amazon-dynamodb
Вопрос:
Я пытаюсь написать лямбда-функцию для добавления новых данных в таблицу DynamoDB. Из чтения документов на:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#put-property Метод PUT: «Создает новый элемент или заменяет старый элемент новым элементом, делегируя его AWS.DynamoDB.PutItem() .»
Помимо выполнения проверки объекта перед «вводом», существует ли параметр или флаг для сбоя, если объект существует при попытке ввода?
Я вижу в
params -> Expected -> Exists (Bool)
но не вижу никакой документации о том, что это делает.
Какая архитектура была бы наилучшей (или быстрой) для предотвращения перезаписи элемента?
Query the table first and if no item exists then add the item
или
Attempt to insert the item and on failure because of duplicate entry report this back? (Is there a way to prevent item overwrite?)
Ответ №1:
ConditionExpression
Может использоваться для проверки того, существуют ли значения ключевого атрибута в таблице, и выполнения операции PUT только в том случае, если значения ключа отсутствуют в таблице.
При первом запуске приведенного ниже кода операция put должна быть успешной. При втором запуске операция put должна завершиться ошибкой с исключением «Ошибка условного запроса«.
В моей таблице movies есть ключи разделения и сортировки. Итак, я использовал оба атрибута в условном выражении.
Пример кода с условным помещением:-
var table = "Movies";
var year = 1502;
var title = "The Big New Movie";
var params = {
TableName:table,
Item:{
"yearkey": year,
"title": title,
"info":{
"plot": "Nothing happens at all.",
"rating": 0
}
},
ConditionExpression: "yearkey <> :yearKeyVal AND #title <> :title",
ExpressionAttributeNames: {
"#title" : "title"
},
ExpressionAttributeValues: {
":yearKeyVal" : year,
":title": {"S": title}
}
};
console.log("Adding a new item...");
docClient.put(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
Исключение при выполнении операции put во второй раз:-
Unable to add item. Error JSON: {
"message": "The conditional request failed",
"code": "ConditionalCheckFailedException",
"time": "2017-10-02T18:26:26.093Z",
"requestId": "7ae3b0c4-3872-478d-908c-94bc9492a43a",
"statusCode": 400,
"retryable": false,
"retryDelay": 0
}
Комментарии:
1. Потрясающе, большое вам спасибо за вашу информацию и помощь!
2. Просто предупреждение (потому что мне потребовалось несколько часов, чтобы найти): этот подход не работает в массовых запросах! Похоже, что условные выражения работают только с отдельными запросами PutItem.
3. Я не понимаю, зачем использовать «И» в «ConditionExpression», а не «ИЛИ», поскольку два элемента, помещенные отдельно, такие как (‘A’, ‘A’) и (‘A’, ‘B’), будут казаться неудачными, поскольку в первом поле произошел сбой, но их следует принять. Однако, правда в том, что независимо от использования «И» или «ИЛИ», результат тот же: «Как только два атрибута не совпадают, и он пройдет».
4. @Chumicat, на самом деле, достаточно просто проверить
yearkey <> :yearKeyVal
без И или ИЛИ. ЭтоConditionExpression
будет проверяться только по уже существующему элементу, который идентифицируется по тому же первичному ключу (что было бы нормально, если бы мы намеревались обновить такой элемент, а не добавлять новый). Это означает, что если Dynamo находит существующую строку для проверки этого условия, мы уже уверены, что хотим, чтобы условие не выполнялось, даже не глядя на его содержимое. Таким образом, любой предикат, который тривиально верен для таких данных, будет работать. Я добавил свой собственный ответ ниже в качестве другого такого примера.5. @spaceemotion,
conditionCheck
действительно, нельзя использоватьBatchWriteItem
, но они могутTransactWriteItems
. В этом случае поведение заключается в том, что если какая-либо проверка завершается неудачей, вся транзакция отменяется. Если в the было выражено несколько условийTransactWriteItems
, и некоторые из них не выполняются, их статус успеха / сбоя указывается в ответе в том же порядке, что и в запросе, который можно использовать для интерпретации происходящего.
Ответ №2:
Я вижу, что этот вопрос относится к языку JavaScript, в любом случае я напишу также для Java (возможно, это будет кому-то полезно):
DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
Map<String, ExpectedAttributeValue> expectedAttributes =
ImmutableMapParameter.<String, ExpectedAttributeValue>builder()
.put("hashKeyAttrName", new ExpectedAttributeValue(false))
.put("rangeKeyAttrName", new ExpectedAttributeValue(false))
.build();
saveExpression.setExpected(expectedAttributes);
saveExpression.setConditionalOperator(ConditionalOperator.AND);
try {
dynamoDBMapper.save(item, saveExpression);
} catch (ConditionalCheckFailedException e) {
e.printStackTrace();
}
ConditionalCheckFailedException
будет выдан в случае, если мы попытаемся сохранить элемент с уже существующей парой HashKey и rangeKey в DynamoDB.
Комментарии:
1. какой ужасный язык
2. почему ужасно? 🙂 это дело привычки, Java — популярный язык программирования)
3. посмотрите на это, это просто уродливо. Мне нравятся типизированные языки, но я чувствую, что во время разработки Java кто-то должен был сказать Стоп! где-то
Ответ №3:
В дополнение к правильному ответу на notionquest рекомендуемый способ выражения условия, которое приводит putItem
к сбою, если элемент уже существует, — это утверждение, что ключ раздела отсутствует ни в одном потенциально существующем элементе:
"ConditionExpression": "attribute_not_exists(pk)",
Это гласит: «если этот элемент уже существует до putItem
, убедитесь, что у него еще нет ключа раздела» ( pk
являющегося ключом раздела в этом примере). Поскольку невозможно, чтобы элемент существовал без ключа раздела, это фактически означает «убедитесь, что этот элемент еще не существует».
Смотрите также блок «Примечание» в начале этой страницы: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/put-item.html
Здесь приведен пример, используемый для гарантии уникальности неключевых столбцов:
Ответ №4:
Как и дополнение к решению @Svend полный пример Java (для AWS SDK v2, dynamodb-enchanced)
public <T> void insert(DynamoDbClient client, String tableName, T object, Class<T> clazz) {
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(client).build();
DynamoDbTable<T> table = enhancedClient.table(tableName, TableSchema.fromBean(clazz));
table.putItem(PutItemEnhancedRequest.builder(clazz)
.item(object)
.conditionExpression(Expression.builder()
.expression("attribute_not_exists(primaryKey)")
.build())
.build());
}
где
primaryKey
- имя столбца, для которого проверяется уникальность
software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException
- исключение, вызванное дублированием
put
- исключение, вызванное дублированием