使用散列键和带有Boto3的范围键查询DynamoDB

时间:2015-10-22 06:12:27

标签: amazon-dynamodb boto3

我无法使用AWS Boto3使用推荐的KeyConditionExpression同时使用哈希键和范围键查询DynamoDB。我附上了一个示例查询:

import boto3
from boto3 import dynamodb
from boto3.session import Session
dynamodb_session = Session(aws_access_key_id=AWS_KEY,
              aws_secret_access_key=AWS_PASS,
              region_name=DYNAMODB_REGION)
dynamodb = dynamodb_session.resource('dynamodb')
table=dynamodb.Table(TABLE_NAME)
request = {
    'ExpressionAttributeNames': {
        '#n0': 'hash_key',
        '#n1': 'range_key'
    },
    'ExpressionAttributeValues': {
        ':v0': {'S': MY_HASH_KEY},
        ':v1': {'N': GT_RANGE_KEY}
    },
    'KeyConditionExpression': '(#n0 = :v0) AND (#n1 > :v1)',
    'TableName': TABLE_NAME
}
response = table.query(**request)

当我使用以下方案对表执行此操作时:

Table Name: TABLE_NAME
Primary Hash Key: hash_key (String)
Primary Range Key: range_key (Number)

我收到以下错误,我无法理解原因:

ClientError: An error occurred (ValidationException) when calling the Query operation: Invalid KeyConditionExpression: Incorrect operand type for operator or function; operator or function: >, operand type: M

根据我的理解,类型M将是一个地图或字典类型,我使用的是类型N,它是一种数字类型,并且我的表格方案与范围键相匹配。如果有人能够解释为什么会发生这种错误,或者我也会采用不同的方式来完成相同的查询,即使你无法解释为什么会出现这种错误。

2 个答案:

答案 0 :(得分:27)

当您使用从boto3.dynamodb.conditions导入的Key和Attr函数时,Boto 3 SDK为您构造条件表达式:

import Ember from 'ember';

export default Ember.Component.extend({
  userGroups: Ember.computed.map('currentuser.individual_groups', function(group, index) {
    return parseInt(group.id);
  }),
  isMember: Ember.computed('groupinfo.id', 'userGroups', function() {
    return this.get('userGroups').contains(parseInt(this.get('groupinfo.id')));
  }),
  ...
});

参考:Step 4: Query and Scan the Data

希望有所帮助

答案 1 :(得分:2)

将此解决方案添加为已接受的答案并没有解决所使用的查询不起作用的原因。

TLDR:与使用 Table 相比,在 boto3 中对 client.query(...) 资源使用查询有细微差别,并且需要不同的语法。

该语法对客户端上的查询有效,但对表无效。表上的 ExpressionAttributeValues 不需要您指定数据类型。此外,如果您对 Table 资源执行查询,则不必再次指定 TableName

工作解决方案:

from boto3.session import Session

dynamodb_session = Session(aws_access_key_id=AWS_KEY,aws_secret_access_key=AWS_PASS,region_name=DYNAMODB_REGION)

dynamodb = dynamodb_session.resource('dynamodb')
table = dynamodb.Table(TABLE_NAME)

request = {
    'ExpressionAttributeNames': {
        '#n0': 'hash_key',
        '#n1': 'range_key'
    },
    'ExpressionAttributeValues': {
        ':v0': MY_HASH_KEY,
        ':v1': GT_RANGE_KEY
    },
    'KeyConditionExpression': '(#n0 = :v0) AND (#n1 > :v1)',
}
response = table.query(**request)

我是一个名为 botoful 的包的作者,它可能有助于避免处理这些复杂性。使用botoful的代码如下:

import boto3
from botoful import Query

client = boto3.Session(
    aws_access_key_id=AWS_KEY,
    aws_secret_access_key=AWS_PASS,
    region_name=DYNAMODB_REGION
).client('dynamodb')

results = (
    Query(TABLE_NAME)
        .key(hash_key=MY_HASH_KEY, range_key__gt=GT_RANGE_KEY)
        .execute(client)
)

print(results.items)