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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31288085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 09:46:05  来源:igfitidea点击:

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

pythonamazon-web-servicesamazon-dynamodbboto

提问by kxxoling

I'm using DynamoDB as an K-V db (cause there's not much data, I think that's fine) , and part of 'V' is list type (about 10 elements). There's some session to append a new value to it, and I cannot find a way to do this in 1 request. What I did is like this:

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

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

I request the server first and save it after modified the value. That's not atomic and looks ugly. Is there any way to do this in one request?

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

采纳答案by LaserJesus

The following code should work with boto3:

以下代码适用于 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']

The get_dynamodb_resource method here is just:

这里的 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'])

回答by Mircea

I would look at update expressions: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html#Expressions.Modifying.UpdateExpressions.ADD

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

Should be doable with an ADD, although not sure what the support in boto is for this.

应该可以使用 ADD,尽管不确定 boto 中的支持是什么。

回答by mkobit

You can do this in 1 request by using the UpdateItemAPI in conjunction with an UpdateExpression. Since you want to append to a list, you would use the SETaction with the list_appendfunction:

您可以通过将UpdateItemAPI 与UpdateExpression. 由于您想附加到列表,您可以使用SET带有list_append函数的操作:

SETsupports 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.

SET支持以下功能:

...

  • list_append (operand, operand)- 评估为添加了新元素的列表。您可以通过反转操作数的顺序将新元素附加到列表的开头或结尾。

You can see a couple examples of this on the Modifying Items and Attributes with Update Expressions documentation:

您可以在使用更新表达式修改项目和属性文档中看到这方面的几个示例:

  • The following example adds a new element to the FiveStarreview list. The expression attribute name #pris ProductReviews; the attribute value :ris 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 FiveStarreview 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)
    
  • 以下示例向FiveStar评论列表添加了一个新元素。表达式属性名称#prProductReviews;属性值:r是一个单元素列表。如果列表之前有两个元素[0][1],那么新元素将是[2]

    SET #pr.FiveStar = list_append(#pr.FiveStar, :r)
    
  • 下面的示例将另一个元素添加到FiveStar评论列表,但这次该元素将附加到列表的开头[0]。列表中的所有其他元素都将移动一个。

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

The #prand :rare using placeholders for the attribute names and values. You can see more information on those on the Using Placeholders for Attribute Names and Values documentation.

#pr:r正在使用的属性名称和值的占位符。您可以在“为属性名称和值使用占位符”文档中查看有关这些内容的更多信息。

回答by rayepps

@LaserJesus 's answer is correct. However, using boto3 directly is kind of a pain, hard to maintain, and not at all reusable. dynamofabstracts that junk away. Using dynamofappending an item to a list attribute would look like:

@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')
  }))

disclaimer: I wrote dynamof

免责声明:我写了dynamof