使用.NET查询Dynamo DB中的二级索引

时间:2017-04-25 12:39:31

标签: c# .net amazon-web-services amazon-dynamodb .net-core

我是一名试图开始使用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: 一个或多个参数值无效:条件参数类型与模式类型不匹配。

任何人都可以就我做错了什么给我一些意见吗?

2 个答案:

答案 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不区分大小写,我预计命中我的查询。无论如何,现在事情正在发挥作用。