我正在尝试了解如何使用DataModel在dynamo中查询表。但是,我找到了两种似乎有效的方法,我找不到正在发生的事情的解释或文档,或者它们之间是否有任何区别。
我发现的方法是使用Filter
或KeyExpression + 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 中的术语"查询筛选条件"特指读取后处理,但您绝对可以应用针对关键属性(并在运行时进行检查)的QueryOperationConfig.Filter
。注释指定键属性与非键属性的事实清楚地表明,这些实际上是读取时键表达式"过滤器",而不是真正意义上的读后过滤器。
当然,这与我们对 DynamoDb 查询的一般了解一致:它们以分区为目标。因此,在哈希键上具有单个筛选条件的 QueryOperationConfig 必须以该分区为目标,并且不可能充当读取后筛选器。否则解释它就是假设实际扫描表然后应用过滤器,这对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);
}
}