internal async Task <IReadOnlyCollection <PartitionKeyRange> > GetPartitionKeyRanges(IDocumentClient client) { string responseContinuation = null; var partitionKeyRanges = new List <PartitionKeyRange>(); var documentCollectionUri = UriFactory.CreateDocumentCollectionUri(this.Database, this.Collection); do { var response = await client.ReadPartitionKeyRangeFeedAsync(documentCollectionUri, new FeedOptions { RequestContinuation = responseContinuation }); partitionKeyRanges.AddRange(response); responseContinuation = response.ResponseContinuation; }while (responseContinuation != null); return(partitionKeyRanges); }
public static async Task <IActionResult> PagedQuery( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "{database}/{collection}")] HttpRequest req, string database, string collection, [CosmosDB("{database}", "{collection}", ConnectionStringSetting = "CosmosDBConnection")] IDocumentClient client, ILogger log, ExecutionContext context) { var functionName = context.FunctionName; var queryString = req.GetQueryParameterDictionary(); var headers = req.GetTypedHeaders(); var pageSize = int.Parse(queryString.ContainsKey("pageSize") ? queryString["pageSize"] : DefaultPageSize.ToString()); var continuation = queryString.ContainsKey("continuation") ? queryString["continuation"] : null; var results = new List <dynamic>(); var cosmosQuery = JObject.Parse(queryString["q"]); var querySpec = new SqlQuerySpec(cosmosQuery["QueryText"]?.ToString(), JsonConvert.DeserializeObject <SqlParameterCollection>(cosmosQuery["Parameters"]?.ToString())); try { Uri collectionUri = UriFactory.CreateDocumentCollectionUri(database, collection); if (string.IsNullOrEmpty(querySpec.QueryText)) { throw new ArgumentNullException("Please provide a query!"); } var response = new PagedResults(); // Loop through partition key ranges foreach (var pkRange in await client.ReadPartitionKeyRangeFeedAsync(collectionUri)) { try { var options = new FeedOptions() { PartitionKeyRangeId = pkRange.Id, RequestContinuation = continuation, MaxItemCount = pageSize - results.Count, ResponseContinuationTokenLimitInKb = ResponseContinuationTokenLimit, EnableCrossPartitionQuery = EnableCrossPartitionQuery }; using (var query = client .CreateDocumentQuery <dynamic>(collectionUri, querySpec, options) .AsDocumentQuery()) { while (query.HasMoreResults && results.Count < pageSize) { // Get results FeedResponse <dynamic> recordSet = await query.ExecuteNextAsync(); foreach (var record in recordSet) { results.Add(record); } // Create Response Object response.Pagination.ContinuationToken = recordSet.ResponseContinuation; // Set Links var referrer = headers.Referer ?? new Uri(req.GetEncodedUrl()); response.Links.Self = referrer.OriginalString; NameValueCollection qc = HttpUtility.ParseQueryString(referrer.Query, Encoding.UTF8); qc.Remove("continuation"); if (!string.IsNullOrEmpty(recordSet.ResponseContinuation)) { qc.Add("continuation", recordSet.ResponseContinuation); response.Links.Next = $"{req.Scheme}://{req.Host}{req.Path}?{string.Join("&", qc.AllKeys.Select(k => string.Format("{0}={1}", k, Uri.EscapeDataString(qc[k]))))}"; } else { response.Links.Next = null; } } } } catch (Exception e) { if (e.Message.Contains("Microsoft.Azure.Documents.Query.CompositeContinuationToken")) { log.LogDebug("Skipping partition key range."); } else { throw; } } } response.Data = results; return(new OkObjectResult(response)); } catch (Exception e) { log.LogError($"{functionName} failed", e); var response = new { e.Message, }; return(new BadRequestObjectResult(response)); } }