使用 .net SDK 查询 DynamoDb table 的正确方法

The correct way to query DynamoDb table with .net SDK

我正在尝试了解如何使用 DataModel 在 dynamo 中查询 table。但是,我发现了两种似乎有效的方法,但我找不到对正在发生的事情或它们之间是否存在任何差异的解释或文档。

我发现的方法是使用 FilterKeyExpression + FilterExpression。有什么区别和正确的做法?

一些示例:

选项 1:

-- 有索引和键

public async Task<List<T>> Find<T>(Guid id)
{
    var query = new QueryOperationConfig
    {
        IndexName = "Table_Id_Index",
        Filter = new QueryFilter("TableId", QueryOperator.Equal, id)
    };

    return await _dynamoDbContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

-- 带索引、键和额外过滤

public async Task<List<T>> Find<T>(Guid id)
{
    var query = new QueryOperationConfig
    {
        IndexName = "Table_Id_Index",
        Filter = new QueryFilter("TableId", QueryOperator.Equal, id)
    };

    query.AddCondition("Deleted", ScanOperator.NotEqual, true);

    return await _dynamoDbContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

-- 使用 GSI、密钥和分区

public async Task<List<T>> Find<T>(Guid id, string partitionKey)
{
    var query = new QueryOperationConfig
    {
        IndexName = "GSI_Index",
        Filter = new QueryFilter("TableId", QueryOperator.Equal, id)
    };

    query.AddCondition("PartitionKey", QueryOperator.Equal, partitionKey);

    return await _dynamoDbContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

选项 2:

-- 有索引和键

public async Task<List<T>> Find<T>(Guid id)
{
    var expressionAttributeValues = new Dictionary<string, DynamoDBEntry>();
    expressionAttributeValues.Add(":v_TableId", id);

    var queryOperationConfig = new QueryOperationConfig
    {
        IndexName = "Table_Id_Index",
        KeyExpression = new Expression
        {
            ExpressionStatement = "TableId = :v_TableId"
            ExpressionAttributeValues = expressionAttributeValues
        }
    };

    var result = await _dynamoDBContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

-- 带索引、键和额外过滤

public async Task<List<T>> Find<T>(Guid id)
{
    var expressionAttributeValues = new Dictionary<string, DynamoDBEntry>();
    expressionAttributeValues.Add(":v_TableId", id);

    var filterAttributes = new Dictionary<string, DynamoDBEntry>();
    filterAttributes.Add(":v_Deleted", true);

    var queryOperationConfig = new QueryOperationConfig
    {
        IndexName = "Table_Id_Index",
        KeyExpression = new Expression
        {
            ExpressionStatement = "TableId = :v_TableId"
            ExpressionAttributeValues = expressionAttributeValues
        }
        FilterExpression = new Expression
        {
            ExpressionStatement = "Deleted != :v_Deleted"
            ExpressionAttributeValues = filterAttributes
        };
    };

    var result = await _dynamoDBContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

-- 使用 GSI、密钥和分区

public async Task<List<T>> Find<T>(Guid id, string partitionKey)
{
    var expressionAttributeValues = new Dictionary<string, DynamoDBEntry>();
    expressionAttributeValues.Add(":v_TableId", id);
    expressionAttributeValues.Add(":v_PartitionKey", partitionKey);

    var queryOperationConfig = new QueryOperationConfig
    {
        IndexName = "GSI_Index",
        KeyExpression = new Expression
        {
            ExpressionStatement = "TableId = :v_TableId and PartitionKey = :v_PartitionKey"
            ExpressionAttributeValues = expressionAttributeValues
        }
    };

    var result = await _dynamoDBContext
        .FromQueryAsync<T>(query)
        .GetRemainingAsync();
}

令人困惑的是,这些选项之间似乎没有什么区别。 AWSSDK.DynamoDBv2 程序集内的注释似乎提供了最好的文档。尽管 DynamoDb 中的术语“查询过滤器”专门指的是 post-read processing,但您绝对可以应用针对关键属性(并在运行时检查)的 QueryOperationConfig.Filter。注释指定关键属性与非关键属性的事实清楚地表明,这些实际上是读取时关键表达式“过滤器”,而不是真正意义上的 post-读取过滤器。

当然这符合我们对 DynamoDb 查询的一般了解:它们以分区为目标。因此,在哈希键上具有单个过滤条件的 QueryOperationConfig 必须以该分区为目标,并且不可能充当 post-read 过滤器。否则解释它就是假设实际扫描 table 然后应用过滤器,这对 Query.

没有任何意义

所以总而言之:DocumentModel提供了两个等价的选项——QueryOperationConfig.KeyExpression选项,它非常清晰但暴露了较低级别的API,以及QueryOperationConfig.Filter选项,它抽象了它混淆了有意义的术语“过滤器”。如果他们设计了一个 KeyExpression 类型,可能会使用 AddHashKeyCondition(...)AddRangeKeyCondition(...) 方法,那就更清楚了。

#region Assembly AWSSDK.DynamoDBv2, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604
// AWSSDK.DynamoDBv2.dll
#endregion

using System.Collections.Generic;
using Amazon.DynamoDBv2.Model;

namespace Amazon.DynamoDBv2.DocumentModel
{
    //
    // Summary:
    //     Query filter.
    public class QueryFilter : Filter
    {
        //
        // Summary:
        //     Constructs an empty QueryFilter instance
        public QueryFilter();
        //
        // Summary:
        //     Constructs an instance of QueryFilter with a single condition. More conditions
        //     can be added after initialization.
        //
        // Parameters:
        //   attributeName:
        //     Target attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     Attributes to compare
        public QueryFilter(string attributeName, QueryOperator op, List<AttributeValue> values);
        //
        // Summary:
        //     Constructs an instance of QueryFilter with a single condition. More conditions
        //     can be added after initialization.
        //
        // Parameters:
        //   attributeName:
        //     Target attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     Attributes to compare
        public QueryFilter(string attributeName, QueryOperator op, params DynamoDBEntry[] values);

        //
        // Summary:
        //     Adds a condition for a specified key attribute that consists of an operator and
        //     any number of AttributeValues.
        //
        // Parameters:
        //   keyAttributeName:
        //     Target key attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     AttributeValues to compare to
        public void AddCondition(string keyAttributeName, QueryOperator op, List<AttributeValue> values);
        //
        // Summary:
        //     Adds a condition for a specified key attribute that consists of an operator and
        //     any number of values
        //
        // Parameters:
        //   keyAttributeName:
        //     Target key attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     Values to compare to
        public void AddCondition(string keyAttributeName, QueryOperator op, params DynamoDBEntry[] values);
        //
        // Summary:
        //     Adds a condition for a specified non-key attribute that consists of an operator
        //     and any number of AttributeValues.
        //
        // Parameters:
        //   nonKeyAttributeName:
        //     Target non-key attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     AttributeValues to compare to
        public void AddCondition(string nonKeyAttributeName, ScanOperator op, List<AttributeValue> values);
        //
        // Summary:
        //     Adds a condition for a specified non-key attribute that consists of an operator
        //     and any number of values
        //
        // Parameters:
        //   nonKeyAttributeName:
        //     Target non-key attribute name
        //
        //   op:
        //     Comparison operator
        //
        //   values:
        //     Values to compare to
        public void AddCondition(string nonKeyAttributeName, ScanOperator op, params DynamoDBEntry[] values);
    }
}