Почему следующая запись DynamoDB с условным выражением выполняется успешно?

У меня есть следующий код для создания таблицы DynamoDB:

def create_mock_dynamo_table():
    conn = boto3.client(
        "dynamodb",
        region_name=REGION,
        aws_access_key_id="ak",
        aws_secret_access_key="sk",
    )
    conn.create_table(
        TableName=DYNAMO_DB_TABLE,
        KeySchema=[
            {'AttributeName': 'PK', 'KeyType': 'HASH'},
            {'AttributeName': 'SK', 'KeyType': 'RANGE'}
        ],
        AttributeDefinitions=[
            {'AttributeName': 'PK', 'AttributeType': 'S'},
            {'AttributeName': 'SK', 'AttributeType': 'S'}],
        ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
    )
    mock_table = boto3.resource('dynamodb', region_name=REGION).Table(DYNAMO_DB_TABLE)
    return mock_table

Затем я использую его для создания двух элементов put-item:

    mock_table = create_mock_dynamo_table()
    mock_table.put_item(
        Item={
            'PK': 'did:100000001',
            'SK': 'weekday:monday:start_time:00:30',
        }
    )
    mock_table.put_item(
        Item={
            'PK': 'did:100000001',
            'SK': 'weekday:monday:start_time:00:40',
        },
        ConditionExpression='attribute_not_exists(PK)'
    )

Когда я делаю второй put_item, PK уже есть в системе, и отличается только ключ сортировки. Но условие я ставлю только в наличии того же PK. Итак, второй put_item должен потерпеть неудачу, верно?


person Sourav Sarkar    schedule 30.04.2020    source источник


Ответы (2)


Проверка условия для PutItem не проверяет условие для произвольных элементов. Он проверяет условие только для элемента с тем же первичным ключом (хеш-ключом и ключом сортировки), если такой элемент существует.

В вашем случае значение ключа сортировки отличается, поэтому, когда вы помещаете второй элемент, DynamoDB видит, что нет элемента с этим ключом, поэтому атрибут PK не существует.

По этой же причине проверка условия дает сбой при втором запуске кода, потому что в этот момент у вас уже есть элемент с таким же хэшем и ключами сортировки.

person Matthew Pope    schedule 04.05.2020

«IOPS» DynamoDB очень низок, и фактическая запись занимает некоторое время. Подробнее об этом можно прочитать здесь. Но если вскоре после этого вы запустите код второй раз, то увидите, что получите ожидаемое botocore.errorfactory.ConditionalCheckFailedException.

Если я могу сослаться на то, что, по моему мнению, вы пытаетесь сделать - смоделируйте БД + данные. Если вы хотите издеваться над таким «дорогим» ресурсом, создайте настоящий поддельный класс. Вы захотите обернуть все ваши обращения к БД в фактический код с помощью какого-то модуля dal.py, который объединяет такие операции, как запись/чтение/и т. д. Затем вы издеваетесь над этими методами/функциями.
Вы не хотите писать код, тесно связанный с выбранной БД.

Лучшей практикой является использование инфраструктуры ORM, такой как SQLAlchemy. Сейчас бесценно потратить время, чтобы изучить его. Но у вас могут быть ограничения по времени, о которых я не знаю.

person edd    schedule 30.04.2020
comment
Я думаю, что ваши рассуждения о задержке неверны. Прежде всего, я действительно попробовал это в реальном DynamoDB, через пару секунд он всегда будет работать. (Я скопировал вырезку из блокнота). Во-вторых, я пробовал это и через мото. В-третьих, позже я получил этот вопрос: заголовок stackoverflow.com/questions/32833351/ Таким образом, это говорит о том, что условное размещение сначала будет искать элемент с заданным хешем и диапазоном. Поскольку в БД нет комбинации хэша и диапазона, мое условие во второй записи становится тривиально true - person Sourav Sarkar; 01.05.2020
comment
@SouravSarkar Тогда я исправлен, ура. Я провел плохой тест и сделал неправильный вывод, хотя сначала подозревал, что ключ всегда неявно обрабатывается парами, но просто не смог найти документацию, подтверждающую это. - person edd; 01.05.2020