我是一名试图开始使用DynamoDB的.NET开发人员。 我花了一些时间尝试通过全局二级索引查询,我发现它比预期更难。我创建了一个表和一个索引。我可以存储项目并通过主键(它是一个guid)将它们取回。我展示了两种不起作用的查询方式。我也试过了几种变体。 我正在使用.NET Core。我的项目有一个MappingId作为主键(一个guid)。但我常常会通过ProductId来查找它们,所以我为此创建了一个辅助全局索引。
这是用于创建表和索引的代码:
private Table CreateTable(string tableName)
{
CreateTableRequest createRequest = null;
if (tableName == "ProductLevelProductPropertyMapping")
{
createRequest = new CreateTableRequest
{
TableName = "ProductLevelProductPropertyMapping",
AttributeDefinitions = new List<AttributeDefinition>()
{
new AttributeDefinition
{
AttributeName = "MappingId",
AttributeType = "S"
} ,
new AttributeDefinition
{
AttributeName = "ProductId",
AttributeType = "N"
}
},
KeySchema = new List<KeySchemaElement>()
{
new KeySchemaElement
{
AttributeName = "MappingId",
KeyType = "HASH"
}
},
GlobalSecondaryIndexes = new List<GlobalSecondaryIndex>()
{
new GlobalSecondaryIndex()
{
IndexName = "ProductIdIdx",
KeySchema = new List<KeySchemaElement>()
{
new KeySchemaElement
{
AttributeName = "ProductId",
KeyType = "HASH"
}
}
}
},
};
}
if (tableName == "SupplierLevelProductPropertyMapping")
{
// Create Something else
.
.
}
// Build a 'CreateTableRequest' for the new table
// Provisioned-throughput settings are required even though
// the local test version of DynamoDB ignores them
createRequest.ProvisionedThroughput = new ProvisionedThroughput(1, 1);
createRequest.GlobalSecondaryIndexes[0].ProvisionedThroughput = new ProvisionedThroughput(1, 1);
createRequest.GlobalSecondaryIndexes[0].Projection = new Projection() { ProjectionType = ProjectionType.ALL };
// Using the DynamoDB client, make a synchronous CreateTable request
try
{
var task = client.CreateTableAsync(createRequest);
task.Wait();
Console.WriteLine("\n\n Created the {0} table successfully!\n Status of the new table: '{1}'", tableName, task.Result.TableDescription.TableStatus);
}
catch (Exception ex)
{
Console.WriteLine("\n Error: failed to create the new table; " + ex.Message);
return null;
}
return Table.LoadTable(client, tableName);
}
我的数据库中有一些项目但是 这种查询方式给出了零点击:
public ProductLevelProductPropertyMapping GetProductLevelItemByProductId(int productId)
{
var request = new QueryRequest
{
TableName = "ProductLevelProductPropertyMapping",
IndexName = "ProductIdIdx",
KeyConditionExpression = "ProductId = :v_Id",
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":v_Id", new AttributeValue { N = productId.ToString() }}}
};
var task = client.QueryAsync(request);
task.Wait();
var result = task.Result.Items; //Zero hits
.
.
//Return some item here
}
我在Amazons文档中看到过类似的例子。但我不清楚他们想要做什么或如何做。 http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSILowLevelDotNet.html#GSILowLevelDotNet.QueryAnIndex
我也尝试过这种方式,但我得到了一个例外:
public ProductLevelProductPropertyMapping GetProductLevelItemByProductId(int productId)
{
var myAttributes = new List<AttributeValue>();
myAttributes.Add(new AttributeValue($"'N' : '{0}' " + productId.ToString()));
var myQF = new QueryFilter("ProductId", QueryOperator.Equal, myAttributes);
var conf = new QueryOperationConfig()
{
IndexName = "ProductIdIdx",
Filter = myQF
};
var someSearchObject = productLevelTable.Query(conf);
var f = someSearchObject.Count;
.
.
//return some result object.
}
第二种查询方式给我一个带有消息的AmazonDynamoDBException: 一个或多个参数值无效:条件参数类型与模式类型不匹配。
任何人都可以就我做错了什么给我一些意见吗?
答案 0 :(得分:1)
对于第二种更高级别的方法,您只需将productId
作为最后一个参数发送到QueryFilter
即可。像这样:
var myQF = new QueryFilter("ProductId", QueryOperator.Equal, productId);
您收到的错误消息表示您的对象类型(List<AttributeValue>
)与索引哈希键类型(数字为N)不匹配。期望的是你发送任何类型的数字,在这种情况下是一个整数。
如果有更多问题,请尝试并回复更新的问题。
<强>更新强>
回答你答案中的推理......
DynamoDB区分大小写,正如Pejus @ AWS在AWS Forum中所述。
我相信发生的事情是你添加了一个字段&#34; productid&#34;到你的文件/项目,然后将其存储在表格中(如你所说)。请注意,您可以在文档中添加任何具有任何名称的字段,而无需在表结构中指定它。所以你可以很好地添加两个字段,如&#34; productid&#34;和&#34; ProductId&#34;在同一时间。
当您查询表时,DynamoDB将根据您的表定义检查您的查询,而不是表中的现有属性。所以,你没有找到任何项目,因为它有一个有效的查询来查找字段&#34; ProductId&#34;,这对于你添加的文档/项目并不存在。因此,查询之前是好的,因为它与表定义匹配,并且逻辑上不返回任何项。它也不应该抛出异常。
无论如何,事情已经解决了。
答案 1 :(得分:0)
感谢您建议的代码行是解决方案的一部分。
var myQF = new QueryFilter("ProductId", QueryOperator.Equal, productId);
让我毫无例外地查询,但仍然是零点击。但也存在套管问题。创建表和索引时,我使用&#34; ProductId&#34;。在存储我正在写的文件时,#produ; productid&#34;像这样:
myDoc["productid"] = item.ProductId;
这似乎导致零命中,但也不例外。但是,如果您尝试查询不存在的属性,则会出现错误。
var myQF = new QueryFilter("SoEasyToGetStarted", QueryOperator.Equal, productId);
然后你会得到一个例外。所以我有点惊讶我混淆了#34; productid&#34;和&#34; ProductId&#34;。如果dynamo不区分大小写,我预计命中我的查询。无论如何,现在事情正在发挥作用。