【问题标题】:Using Cosmos DB Table API to query for a datetime range使用 Cosmos DB 表 API 查询日期时间范围
【发布时间】:2021-11-05 13:11:05
【问题描述】:

我正在使用 Cosmos DB 表 API 来管理我的数据(使用 SQL API 不是一个选项)。我使用“创建日期时间刻度”作为“分区键”。这个想法是每半小时检索一次数据。为了得到半小时范围内的新数据,我写了一个方法,是这样的—— (更新 - 根据 Gaurav 的建议,我更新了代码)。

public async Task<List<TEntity>> GetEntityWithDateTimePartitionKeyAsync<TEntity>(long startDateTimeTicks , long endDateTimeTicks, string tableName) where TEntity : TableEntity, new()
        {
            var results = new List<TEntity>();
            if (endDateTimeTicks > startDateTimeTicks)
            {
                var table = await this.GetTableAsync(tableName, true).ConfigureAwait(false);               
                 var filterA = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.GreaterThanOrEqual, startDateTimeTicks.ToString());
                 var filterB = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.LessThan, endDateTimeTicks.ToString());
                  var combinedFilter = TableQuery.CombineFilters(filterA, "AND", filterB);
                   var query = new TableQuery<TEntity>().Where(combinedFilter);         
              

                try
                {
                    results = table.ExecuteQuery<TEntity>(query).ToList();                   
                }
                catch(Exception ex)
                {
                }
            }
            return results;
        }

// Sample Data - 
public class TestItem: TableEntity
{
}

//Create the instances and then save them to Cosmos Db.
var testItem1 = new TestItem { PartitionKey ="637671350058032346",RowKey= "Mumbai", ETag="*" };
var testItem2 = new TestItem {PartitionKey = "637671350058033346", RowKey="Delhi" , ETag="*"};
var testItem3 = new TestItem { PartitionKey ="637671350058034346", RowKey="Chennai" , ETag="*"};
var testItem4 = new TestItem { PartitionKey ="637671350058035346", RowKey="Hyderabad" , ETag="*"}

//Calling the method -
var entityList = await GetEntityWithDateTimePartitionKeyAsync<TestItem>(637671350058030000 , 637671350058036000, "TestTable");

` 我遇到了一个异常-“来自程序集'Microsoft.Azure.Cosmos.Table,Version=1.0.8.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35'的'QueryTokenVisitor'类型的方法'Visit'没有实现。”。 我也尝试使用 LINQ 查询。但我无法让它工作。 我尝试的另一件事是 TableQuery.GenerateFilterCondition()。这适用于特定的“PartitionKey”和“RowKey”,但不适用于“PartitionKey”的范围。 如何使用 Cosmos DB Table API 获取给定 DateTime 范围的结果?我是 Azure 表 API 的新手。

【问题讨论】:

    标签: azure-functions azure-cosmosdb azure-table-storage azure-tablequery azure-cosmosdb-tables


    【解决方案1】:

    您的代码存在一些问题:

    1. PartitionKey 的类型为 string,而您正在创建基于 long 的筛选条件。您的过滤条件将产生像 PartitionKey ge {startDateTimeTicks}LPartitionKey lt {endDateTimeTicks}L 这样的 ODATA 查询。您需要使用如下代码:
    var filterA = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.GreaterThanOrEqual, startDateTimeTicks.ToString());
    var filterB = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.LessThan, endDateTimeTicks.ToString());
    
    1. 您在创建查询时缺少连接这两个过滤器的逻辑连接器(在您的情况下为AND)。因此,您的query 看起来像PartitionKey lt {endDateTimeTicks}L(基本上它只是接听filterB)。您需要结合这两个过滤条件并在查询中使用它:
    var combinedFilter = TableQuery.CombineFilters(filterA, "AND", filterB);
    var query = new TableQuery<DynamicTableEntity>().Where(combinedFilter);
    

    当您这样做时,您的查询将如下所示:

    (PartitionKey ge '{startDateTimeTicks}') AND (PartitionKey lt '{endDateTimeTicks}')
    

    这个查询应该会给你数据。

    更新

    我无法重现该问题。这是我使用的代码,它给了我正确的结果。

    using System;
    using System.Threading.Tasks;
    using Microsoft.Azure.Cosmos.Table;
    using Newtonsoft.Json;
    
    namespace CosmosDbTableSamples
    {
        class Program
        {
            static async Task Main(string[] args)
            {
                string accountName = "accountname";
                string accountKey =
                    "accountkey";
                string tableUrl = "https://accountname.table.cosmos.azure.com:443/";
                string tableName = "Test";
                StorageCredentials credentials1 = new StorageCredentials();
                
                StorageCredentials credentials = new StorageCredentials(accountName, accountKey);
                CloudTableClient tableClient = new CloudTableClient(new Uri(tableUrl), credentials);
                CloudTable table = tableClient.GetTableReference(tableName);
                long startDateTimeTicks = 637671350058030000, endDateTimeTicks = 637671350058036000;
                var filterA = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.GreaterThanOrEqual, startDateTimeTicks.ToString());
                var filterB = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.LessThan, endDateTimeTicks.ToString());
                var combinedFilter = TableQuery.CombineFilters(filterA, "and", filterB);
                var query = new TableQuery<TestItem>().Where(combinedFilter);
                var result = await table.ExecuteQuerySegmentedAsync<TestItem>(query, null);
                foreach (var row in result)
                {
                    Console.WriteLine($"{row.PartitionKey}|{row.RowKey}");
                }
            }
        }
        
        public class TestItem: TableEntity
        {
        }
    }
    

    我使用了Microsoft.Azure.Cosmos.Table (1.0.8) SDK。

    【讨论】:

    • 谢谢高拉夫。差不多了。现在,得到一个异常-“来自程序集'Microsoft.Azure.Cosmos.Table,Version = 1.0.8.0,Culture = Neutral,PublicKeyToken = 31bf3856ad364e35'的'QueryTokenVisitor'类型的方法'Visit'没有实现。”。这个错误似乎也出现在较新的 Nuget 包中。任何想法,哪个 Nuget 版本不会有这个问题?有什么办法吗?
    • 我第一次看到这个错误。您可以编辑您的问题并包含更新的代码吗?另外,请分享一些示例数据。
    • Gaurav,我更新了帖子并添加了示例代码。如果您第一次看到该错误,那么我的代码中有问题。您能否添加一个小示例代码作为参考?谢谢
    • 不幸的是,我无法重现该问题。用我使用的代码更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 2019-05-26
    • 2018-12-17
    • 2019-11-14
    相关资源
    最近更新 更多