如何将值附加到 AWS DynamoDB 上的列表属性?

How to append a value to list attribute on AWS DynamoDB?

我将 DynamoDB 用作 K-V 数据库(因为数据不多,我认为这很好),'V' 的一部分是列表类型(大约 10 个元素)。有一些会话可以为其附加新值,但我无法在 1 个请求中找到执行此操作的方法。我做的是这样的:

item = self.list_table.get_item(**{'k': 'some_key'})
item['v'].append('some_value')
item.partial_save()

我先请求服务器,修改值后保存。那不是原子的,看起来很丑。有什么办法可以在一个请求中做到这一点吗?

我会看看更新表达式: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html#Expressions.Modifying.UpdateExpressions.ADD

应该可以使用 ADD,但不确定 boto 对此的支持是什么。

您可以使用 UpdateItem API in conjunction with an UpdateExpression 在 1 个请求中完成此操作。因为你想追加到一个列表,你可以使用 SET 操作和 list_append 函数:

SET supports the following functions:

...

  • list_append (operand, operand) - evaluates to a list with a new element added to it. You can append the new element to the start or the end of the list by reversing the order of the operands.

您可以在 Modifying Items and Attributes with Update Expressions documentation 上看到几个这样的例子:

  • The following example adds a new element to the FiveStar review list. The expression attribute name #pr is ProductReviews; the attribute value :r is a one-element list. If the list previously had two elements, [0] and [1], then the new element will be [2].

    SET #pr.FiveStar = list_append(#pr.FiveStar, :r)
    
  • The following example adds another element to the FiveStar review list, but this time the element will be appended to the start of the list at [0]. All of the other elements in the list will be shifted by one.

    SET #pr.FiveStar = list_append(:r, #pr.FiveStar)
    

#pr:r 对属性名称和值使用占位符。您可以在 Using Placeholders for Attribute Names and Values documentation.

上查看更多信息

以下代码应该适用于 boto3:

table = get_dynamodb_resource().Table("table_name")
result = table.update_item(
    Key={
        'hash_key': hash_key,
        'range_key': range_key
    },
    UpdateExpression="SET some_attr = list_append(some_attr, :i)",
    ExpressionAttributeValues={
        ':i': [some_value],
    },
    ReturnValues="UPDATED_NEW"
)
if result['ResponseMetadata']['HTTPStatusCode'] == 200 and 'Attributes' in result:
    return result['Attributes']['some_attr']

这里的get_dynamodb_resource方法就是:

def get_dynamodb_resource():
    return boto3.resource(
            'dynamodb',
            region_name=os.environ['AWS_DYNAMO_REGION'],
            endpoint_url=os.environ['AWS_DYNAMO_ENDPOINT'],
            aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
            aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'])

@LaserJesus 的回答是正确的。然而,直接使用 boto3 是一种痛苦,难以维护,而且根本不可重用。 dynamof 抽象那些垃圾。使用 dynamof 将项目附加到列表属性看起来像:

from functools import partial
from boto3 import client
from dynamof.executor import execute
from dynamof.operations import update
from dynamof.attribute import attr

client = client('dynamodb', endpoint_url='http://localstack:4569')
db = partial(execute, client)

db(update(
  table_name='users',
  key={ 'id': user_id },
  attributes={
      'roles': attr.append('admin')
  }))

免责声明:我写了 dynamof