Как условно вставить элемент в таблицу dynamodb с помощью boto3

Если у меня есть таблица с хэш-ключом userId и ключ диапазона productId, как я могу поместить элемент в эту таблицу, только если он еще не существует с помощью привязок boto3 dynamodb?

Обычный вызов put_item выглядит следующим образом:

table.put_item(Item={'userId': 1, 'productId': 2})

Мой вызов с выражением ConditionExpression выглядит так:

table.put_item(
    Item={'userId': 1, 'productId': 2}, 
    ConditionExpression='userId <> :uid AND productId <> :pid', 
    ExpressionAttributeValues={':uid': 1, ':pid': 3}
)

Но каждый раз возникает исключение ConditionalCheckFailedException. Существует ли элемент с одним и тем же продуктом или нет.

Ответ 1

Документация для этого, к сожалению, не очень понятна. Мне нужно было что-то сделать, и вот что для меня работало, используя boto3:

try:
    table.put_item(
        Item={
            'foo':1,
            'bar':2,
        },
        ConditionExpression='attribute_not_exists(foo) AND attribute_not_exists(bar)'
    )
except botocore.exceptions.ClientError as e:
    # Ignore the ConditionalCheckFailedException, bubble up
    # other exceptions.
    if e.response['Error']['Code'] != 'ConditionalCheckFailedException':
        raise

Подобно другому ответу, ключ находится в функции attribute_not_exists, но сначала мне было непонятно, как заставить это работать. После некоторых экспериментов я смог добиться этого.

Ответ 2

Я думаю, что вы получите лучшую документацию, используя client.put_item, а не table.put_item

из документации boto3:

Чтобы предотвратить замену нового элемента на существующий элемент, используйте условное выражение, содержащее функцию attribute_not_exists, с именем атрибута, используемого в качестве ключа раздела для таблицы. Поскольку каждая запись должна содержать этот атрибут, функция attribute_not_exists будет успешной только в том случае, если соответствующий элемент не существует.

ConditionExpression:

ConditionExpression (string) - условие, которое должно выполняться для успешного выполнения операции условного ввода.

Выражение может содержать любое из следующего:

Функции: attribute_exists | attribute_not_exists | attribute_type | содержит | begin_with | size Эти имена функций чувствительны к регистру.

Я использую параметр переопределения item.save() на item.save()