在给定主分区键值列表的情况下,如何一次批处理多个项目

Hil*_*ers 4 python boto amazon-dynamodb boto3

因此,我有一个带有主分区键列的dynamodb表,foo_id而没有主排序键。我有一个foo_id值列表,并且想要获得与此ID列表关联的观察值。

我认为执行此操作(?)的最佳方法是使用batch_get_item(),但对我而言并不奏效。

    # python code
    import boto3
    client = boto3.client('dynamodb')

    # ppk_values = list of `foo_id` values (strings) (< 100 in this example)
    x = client.batch_get_item(
        RequestItems={
            'my_table_name':
                {'Keys': [{'foo_id': {'SS': [id for id in ppk_values]}}]}
        })
Run Code Online (Sandbox Code Playgroud)

我正在使用,SS因为我传递的是字符串列表(foo_id值列表),但是我得到了:

ClientError: An error occurred (ValidationException) when calling the
BatchGetItem operation: The provided key element does not match the
schema
Run Code Online (Sandbox Code Playgroud)

因此,我认为这意味着它在考虑foo_id包含列表值而不是字符串值,这是错误的。

->这样的解释正确吗?批查询一堆主分区键值的最佳方法是什么?

小智 10

Boto3 现在有一个版本batch_get_item,可以让您以更自然的 Pythonic 方式传递键,而无需指定类型。

您可以在https://github.com/awsdocs/aws-doc-sdk-examples 中找到完整且有效的代码示例。该示例处理有关重试的一些其他细微差别,但这里是回答此问题的代码部分的摘要:

import logging
import boto3

dynamodb = boto3.resource('dynamodb')
logger = logging.getLogger(__name__)

movie_table = dynamodb.Table('Movies')
actor_table = dyanmodb.Table('Actors')

batch_keys = {
    movie_table.name: {
        'Keys': [{'year': movie[0], 'title': movie[1]} for movie in movie_list]
    },
    actor_table.name: {
        'Keys': [{'name': actor} for actor in actor_list]
    }
}

response = dynamodb.batch_get_item(RequestItems=batch_keys)

for response_table, response_items in response.items():
    logger.info("Got %s items from %s.", len(response_items), response_table)
Run Code Online (Sandbox Code Playgroud)


mcs*_*ner 7

批准的答案不再有效。

对我来说,工作呼叫格式如下:

import boto3
client = boto3.client('dynamodb')

# ppk_values = list of `foo_id` values (strings) (< 100 in this example)
x = client.batch_get_item(
    RequestItems={
        'my_table_name': {
            'Keys': [{'foo_id': {'S': id}} for id in ppk_values]
        }
    }
)
Run Code Online (Sandbox Code Playgroud)

需要类型信息。对我来说,“S”代表字符串键。如果没有它,我会收到一条错误消息,指出库找到了一个,str但需要一个dict. 也就是说,他们想要的{'foo_id': {'S': id}}不是{'foo_id': id}我首先尝试的更简单的。


not*_*est 6

密钥应如下所述。它不能被称为“ SS”。

基本上,您可以将DynamoDB String数据类型与String进行比较(即,不能与SS进行比较)。每个项目都单独处理。它在查询中与SQL不同

'Keys': [
            {
                'foo_id': key1
            },
            {
                'foo_id': key2
            }
], 
Run Code Online (Sandbox Code Playgroud)

示例代码:-

您可能需要更改表名称和键值。

from __future__ import print_function # Python 2/3 compatibility
import boto3
import json
import decimal
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

# Helper class to convert a DynamoDB item to JSON.
class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        return super(DecimalEncoder, self).default(o)

dynamodb = boto3.resource("dynamodb", region_name='us-west-2', endpoint_url="http://localhost:8000")

email1 = "abc@gmail.com"
email2 = "bcd@gmail.com"

try:
    response = dynamodb.batch_get_item(
        RequestItems={
            'users': {
                'Keys': [
                    {
                        'email': email1
                    },
                    {
                        'email': email2
                    },
                ],            
                'ConsistentRead': True            
            }
        },
        ReturnConsumedCapacity='TOTAL'
    )
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    item = response['Responses']
    print("BatchGetItem succeeded:")
    print(json.dumps(item, indent=4, cls=DecimalEncoder))
Run Code Online (Sandbox Code Playgroud)

  • 仅当将dynamodb.batch_get_item更改为dynamodb.meta.client.batch_get_item时,以上答案才有效,因为batch_get_item方法仅存在于客户端上而不存在于资源上。 (4认同)
  • 对于任何为此苦苦挣扎的人,有一个重要的点需要注意,我忽略了这一点,那就是“主键”一词的使用,因此如果您的主键由分区键和排序键组成,那么您必须提供**两者**!(遗憾的是,这使我的用例毫无用处)。否则,您将收到“ValidationException 提供的关键元素与架构不匹配”错误。 (2认同)