DynamoDB:所提供的键元素与模式不匹配。

66

有没有一种方法可以根据不是哈希键的字段获取项目?

例子

我的用户表:id(HashKey),name,email

我想检索具有电子邮件为'test@mail.com'的用户

怎么做到这一点?

我尝试使用Boto:

user = users.get_item(email='john.doe@gmail.com')

我遇到了以下错误:

'The provided key element does not match the schema'
12个回答

59
以下适用于AWS Lambda环境中的Node.js AWS SDK:
对我来说,这是一个棘手的问题。在尝试使用getItem方法时,我遇到了这个问题。不管我尝试什么,我都会继续收到这个错误。最终我在AWS论坛上找到了解决方案:https://forums.aws.amazon.com/thread.jspa?threadID=208820 令人费解的是,这个看似解决方案与我能找到的所有AWS文档都有冲突。
以下是对我有效的代码:
var doc = require('dynamodb-doc');
var dynamo = new doc.DynamoDB();

var params = { }
params.TableName = "ExampleTable";
var key = { "ExampleHashKey": "1" };
params.Key = key;

dynamo.getItem(params, function(err, data) {
    if (err)
        console.log(err);
    else
        console.log(data)
});

25
谢谢!问题确实是AWS文档要求提供一个打包对象(例如 var key = { "ExampleHashKey": { "S": "1" } }),而实际的SDK需要一个普通的JavaScript对象(例如 var key = { "ExampleHashKey": "1" })。这也发生在“update”/“updateItem”方法中。 - aviggiano
17
DynamoDB的文档一直是个难题。我认为问题的根源在于基础的DynamoDB客户端和更高级的Document Client之间的区别。基础客户端使用AttributeValues,例如var key = { S: { name: 'joe' } },而Document Client使用本地JavaScript对象,例如var key = { name: 'joe' }。 - jarmod
在Ruby文档的情况下 https://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#get_item-instance_method 似乎有点混淆,因为Aws::DynamoDB::Client类的示例包含了相同的问题,即描述了一个已编组的值,但实际上期望处理一个典型的哈希。 - Mark Fox
ExampleHashKey是数据条目的ID。它旁边的1代表什么? - gorilla bull
2
请注意:显然,这个解决方案已经不再起作用了,现在AWS SDK的行为符合文档,所以您的示例现在应该是正确的形式:var key = {"ExampleHashKey": {S: "1"}}; - gregn3
这篇博客可以帮助你理解客户端之间的差异,如果使用不当可能会导致问题。请点击链接查看:https://aws.amazon.com/blogs/database/exploring-amazon-dynamodb-sdk-clients/ - undefined

25
要查询不是散列键的字段,您需要使用全局二级索引(GSI)。查看这篇AWS文章以了解有关GSI的更多详细信息。 更新 2015 年 2 月:现在可以将GSI添加到现有表中。有关更多详细信息,请参阅Amazon文档遗憾的是您不能在现有的DynamoDB表中添加GSI,因此如果这是您真正需要查询的内容,则需要创建新表并迁移数据。DynamoDB FAQ中得知:

问:如何为DynamoDB表创建全局二级索引?

与表相关联的所有GSI必须在表创建时指定。 此时,在表创建后添加GSI是不可能的。有关创建表及其索引的详细步骤,请参见此处。您可以为每个表创建最多5个全局二级索引

如果您不想迁移数据,可以考虑创建第二个 DynamoDB 表格,其中电子邮件地址作为哈希键,父记录的哈希值用作在主数据表中查找的关键,但是正如您所想象的那样,这并不是一个最佳解决方案,并且它有自己的麻烦,需要保持与主表同步。

谢谢Wolfwyrd..现在很多事情对我来说都很清楚了。 - user1635536
3
这是一篇较旧的回答,但如果有人找到这个答案,现在可以在现有表上创建全局索引。局部索引仍然必须在创建时设置。 - Kris White

15

当我发送字符串而不是整数时,我也遇到了这个错误。

当然,这是在写入数据库而不是从中读取时发生的。


在我的情况下,使用baopham/laravel-dynamodb,我必须使用(string)和(integer)来明确类型:$model = ModelData::where('PartitionKey', (string)$SearchPartitionKey)->where('SortKey',(integer)$SearchSortKey)->get(); - Cristian Sepulveda

13

我在表中有一个分区键(partition key)和排序键(sort key)。

之前只使用了分区键进行查询,但出现了错误。

显然,使用复合键进行查询解决了这个问题。


3
创建表时,有一个字段叫做“分区键”和一个字段叫做“排序键(可选)”。如果你在“排序键”字段中输入了内容,那么在使用主键进行调用(例如get_item)时,你需要使用它。
举个例子,如果我的分区键是“姓名”,而我的排序键是“姓氏”,我需要这样调用它:
var params = {
  TableName: 'mytable',
  Key: {
    'name': {S: 'John'},
    'surname': {S: 'Sena'}
  }
};

如果您只使用主键的第一部分(姓名)对该表进行get_item调用,您将会收到“提供的键元素与模式不匹配”的错误提示,因为缺少姓氏。
要解决此问题,请在调用中添加排序键(或重新创建没有排序键的表)。

2

我在Java中遇到了这个错误,因为我在RANGE键上使用了@DynamoDBHashKey注释。我需要使用@DynamoDBRangeKey注释来代替对象的ID。


1

我的AWS Lambda函数出现了这个错误,因为我的参数是BigInt类型,需要转换为Number类型。我进行了如下更改:

let data = await docClient.get({ TableName: "items", Key: { "accountid": accountId, "itemid": itemId } }).promise();

...转化为以下内容:

let data = await docClient.get({ TableName: "items", Key: { "accountid": Number(accountId), "itemid": Number(itemId) } }).promise();

1
当您在表中定义键或值与模式不符时,会发生异常提供的键元素与模式不匹配
原始问题是想根据非键属性获取项目,但由于分区键名称不对齐,所以出现了异常。
要解决此问题,您需要在非键属性上创建全局二级索引(GSI)。由于GSI中的项目不需要唯一,您将失去使用GetItem API的能力,而必须使用Query API,该API允许您检索与键匹配的多个项目(如果存在)。
当前评分最高的答案与问题不一致,但产生相同的异常提供的键元素与模式不匹配是由于高级和低级客户端之间的差异。高级客户端接受JSON值,而低级客户端接受DynamoDB-JSON。混合使用这些参数将导致异常。这些差异在以下博客文章中有详细说明:

https://aws.amazon.com/blogs/database/exploring-amazon-dynamodb-sdk-clients/


1

在我的Java应用程序中,我遇到了这个错误,因为我在DAO类中不小心注释了两个范围键(@DynamoDBRangeKey),但实际上只应该有一个。我将新添加的注释更改为@DynamoDBAttribute,问题得以解决。


1
在使用 DynamoDB 的过程中,如果你刚开始使用并且遇到了以下错误:GetItemCommand 仅提供分区键的值,并且该表具有复合主键,则需要同时指定排序键的值以检索匹配该组合的单个记录,或者切换到 QueryCommand 以返回与分区键匹配的任何内容,而不考虑排序键。希望这可以帮助其他初学者解决问题。请注意保留 HTML 标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接