niicck
niicck

Reputation: 101

Can we use transact_write_items without specifying attribute types?

According to the boto3 official documentation, the transact_write_items method is only available on the dynamodb client, not the dynamodb ServiceResource. The nice thing about methods on the dynamodb ServiceResource vs the client is that ServiceResource methods don't require you to parse your own attribute types. You can plug in a basic python dictionary as an item rather than needing to specify every value's attribute type.

Here's an example of using a client to insert an item:

import boto3
client = boto3.client('dynamodb')
client.put_item(
    Item={
        'AlbumTitle': {
            'S': 'Somewhat Famous',
        },
        'Artist': {
            'S': 'No One You Know',
        },
        'SongTitle': {
            'S': 'Call Me Today',
        },
        'NestedValue': {
            'M': {
                'a': {'S': 'apple'},
                'b': {'L': [
                    {'S': 'something else'},
                    {'S': 'another value'}
                ]}
            }
    },
    ReturnConsumedCapacity='TOTAL',
    TableName='Music',
)

Here's an example of using a ServiceResource to insert an item:

import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Music')
table.put_item(
    Item={
        'AlbumTitle': 'Somewhat Famous',
        'Artist': 'No One You Know',
        'SongTitle': 'Call Me Today',
        'NestedValue': {
            'a': 'apple',
            'b': [
                'something else',
                'another value'
            ]
        }
    },
)

It is much cleaner to use a dynamodb ServiceResource, especially for complicated nested values. As a workaround, I've been writing a parser that converts a python dictionary into a dynamodb-digestible dictionary. This should work, but it wouldn't be as simple or secure as letting boto3 handle that for me. This is all because transact_write_items is not available on a ServiceResource.

Unless it is? A dynamodb ServiceResource dynamodb = boto3.resource('dynamodb') has a client inside it's meta object. dynamodb.meta.client.transact_write_items is a valid, seemingly functional instance of transact_write_items. And it seems to automatically parse my item dictionary without needing to specify attribute types.

import boto3
dynamodb = boto3.resource('dynamodb')
dynamodb.meta.client.transact_write_items(Items=[
    {
        "Put": {
            "TableName": "test",
            "Item": {
                "pk": "a",
                "sk": "b"
            },
            "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
        }
    }
])

vs.

import boto3
client = boto3.client('dynamodb')
client.transact_write_items(Items=[
    {
        "Put": {
            "TableName": "test",
            "Item": {
                "pk": {"S": "a"},
                "sk": {"S": "b"}
            },
            "ReturnValuesOnConditionCheckFailure": "ALL_OLD",
        }
    }
])

Is this a viable solution? Can I use dynamodb.meta.client.transact_write_items to use transact_write_items with all the automated attribute parsing benefits that come from using ServiceResource methods? Are there unintended side effects that I'm not aware of? It doesn't feel right calling a method nested deep into the meta attribute, but I can't find another cleaner way to get what I'm looking for.

Documentation that might help:

Upvotes: 6

Views: 4194

Answers (1)

niicck
niicck

Reputation: 101

Apparently this is the expected behavior of boto3. One developer's bug is another developer's feature.

https://github.com/boto/boto3/issues/2391

Upvotes: 2

Related Questions