如何允许将 Odata 选项应用于 cosmos db 集合并返回过滤后的记录

Posted

技术标签:

【中文标题】如何允许将 Odata 选项应用于 cosmos db 集合并返回过滤后的记录【英文标题】:How to allow Odata options to be applied to cosmos db collection and return filtered records 【发布时间】:2020-11-30 05:10:15 【问题描述】:

我需要在 api 上实现分页。我正在执行以下操作以在 api 上启用 OData 查询,但它在从 cosmos db 获取所有记录后进行过滤,但我想从 cosmos db 中获取过滤后的记录。如何将 Odata 查询选项转换为 cosmos db 查询选项?

 controller.cs

            [Route("apps")]
            [HttpGet]
            [EnableQuery]
            public async Task<IActionResult> GetAllApps(CancellationToken cancellationToken)
            
                var user = this.GetUser();
                var results = await this.appRepository.GetAppsForUserAsync(user, cancellationToken).ConfigureAwait(false);
                return this.Ok(this.mapper.Map<AppHeader[]>(results));
            
AppRepository.cs
 public async Task<IEnumerable<App>> GetAppsForUserAsync(User user, CancellationToken cancellationToken)
                    
            try
            
                FeedOptions queryOptions = new FeedOptions
                
                    MaxItemCount = -1,
                    PartitionKey = new PartitionKey(user)
                ;

                var query = this.factory.GetClient()
                    .CreateDocumentQuery<App>(
                        UriFactory.CreateDocumentCollectionUri(DatabaseName, CollectionName),
                        queryOptions)
                    .Where(resource => resource.UserList.Any(u => u.userId == user.Id))
                    .AsDocumentQuery();

                List<App> results = new List<App>();
                while (query.HasMoreResults)
                
                    cancellationToken.ThrowIfCancellationRequested();

                    var response = await query.ExecuteNextAsync<App>(cancellationToken).ConfigureAwait(false);

                    var app = this.mapper.Map<App[]>(response);
                    results.AddRange(app);
                

                return results;
            
            catch (DocumentClientException ex)
            
                this.logger.LogError(ex, ex.Message);
                throw;
            
        
Client.js

http://localhost:8303/api/appdefinitions/my?$skip=6&$top=4`

【问题讨论】:

【参考方案1】:

在存储库中,尝试使用GetItemLinqQueryable 并对其进行查询。请注意,我在这里使用的是较新的 V3 SDK Microsoft.Azure.Cosmos,但旧版 SDK 中也应该存在等效项。

// Take `skip` and `top` params as input to the repository method.

List<App> results = new List<App>();
using (CosmosClient client = new CosmosClient(endpoint, authKey))

  Database cosmosDatabase = await client.CreateDatabaseIfNotExistsAsync(DatabaseName);
  Container container = await Program.GetOrCreateContainerAsync(cosmosDatabase, CollectionName);
  // LINQ query generation
  using (FeedIterator setIterator = container.GetItemLinqQueryable<App>()
                     .Where(a => a.userId == user.Id)
                     .Skip(skip)
                     .Take(top)
                     .ToFeedIterator())
                     
      //Asynchronous query execution
      while (setIterator.HasMoreResults)
      
          var items = await feedIterator.ReadNextAsync().ConfigureAwait(false);
          results.AddRange(items);
      
  

注意:理想情况下,在实际应用程序中,您应该重用 CosmosClient 实例,而不是每次都为 performance improvement 创建。

【讨论】:

感谢您的回答!。我会考虑这一点,但是如何将 skip 和 top 参数作为输入传递给存储库方法?如何建模从客户端到控制器的绑定跳过和顶部? 您可以通过控制器操作绑定到ODataQueryOptions 模型。 我同意您的选择,但就我而言,我想在不使用更新的 V3 SDK Microsoft.Azure.Cosmos 的情况下实现该功能

以上是关于如何允许将 Odata 选项应用于 cosmos db 集合并返回过滤后的记录的主要内容,如果未能解决你的问题,请参考以下文章