Jaya
Jaya

Reputation: 3911

Document Db Request Continuation Token Not set on the 1st iteration

I have a document db collection that contains about 1500 docs. My eventual goal is to build an api with the above as my persistence layer. I read the docs (https://azure.microsoft.com/en-us/blog/documentdb-paging-support-with-top-and-more-query-improvements/) that mentions to use request continuation token via feed options for paging.

Have the following method on a console app to understand the same: The problem or the issue here is that the first time the query is executed the continuation token=null but the second time the query is executed the continuation token = "some value"

So my question is shouldn't the continuation token be set the first time itself? or am I missing something obvious

    //field
    private static readonly FeedOptions DefaultOptions = new FeedOptions {     EnableCrossPartitionQuery = true,MaxItemCount = 1};
    //method
 private static async Task<bool> QueryItemDocuments(string collectionLink)
    {

        IDocumentQuery<Item> query = client.CreateDocumentQuery<Item>(collectionLink, new SqlQuerySpec()
        {
            QueryText = "SELECT * FROM items",
        },DefaultOptions).AsDocumentQuery();

        var loopNumber = 0;
        while (query.HasMoreResults)
        {
            loopNumber++;
            var results=(await query.ExecuteNextAsync<Item>()).ToList();
            Console.WriteLine("Count {0}",results.Count);
            Console.WriteLine("Loopnumber :{0} Token {1}", loopNumber, DefaultOptions.RequestContinuation ?? "Null");

            Console.WriteLine("Id: {0},Name: {1}", results[0].Id, results[0].Name);
        }
        return query.HasMoreResults;
    }

sample results from console :
       Count 1
       Loopnumber :1 Token Null //why is this null?
       Id: 1dbaf1d0-0125-11e0-88a8-005056957023,Name:Energy Drink
       Count 1
       Loopnumber :2 Token -       RID:jq4gAIZqMwACBBBBBBB==#RT:1#TRC:1#PKRID:0
       Id: 244a8230-0231-11e0-8c8b-005056957023,Name: Gluten Free Dish

Edits: Ideally, I would send back the continuation token on the response headers allowing the client to fetch more if needed (on my web api) - so my method would like

     public Get(int? page=1,int? size=20)

so when I send the response back with the first 20 I need to send back the continuation token for the client to request more: so if the continuation token is not set the first time - meaning when I retrieve the 1st batch of 20, how do I do this?

Upvotes: 1

Views: 3245

Answers (2)

Jaya
Jaya

Reputation: 3911

okay, so i figured that it might be a bug in the SDK or by design - do not know, however when I query for the result using Document Db's rest end points - the continuation token is indeed set on the first batch's response. Here is the sample code that used:

   private static async Task QueryItemDocumentsUsingRestApi()
    {
       //About rest end points to query documents here https://msdn.microsoft.com/en-us/library/azure/mt670897.aspx
        IEnumerable<string> continuationTokens = null;
        var continToken = string.Empty;
        var verb = "POST";
        var resourceType = "docs";
        var resourceLink = string.Format("dbs/{0}/colls/{1}/docs", DatabaseName, CollectionName);
        var resourceId = string.Format("dbs/{0}/colls/{1}", DatabaseName, CollectionName)
        var authHeader = GenerateAuthSignature(verb, resourceId, resourceType, authorizationKey, "master", "1.0"); // look here for how this is generated https://github.com/Azure/azure-documentdb-dotnet/blob/master/samples/rest-from-.net/Program.cs

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("x-ms-date", _utcDate);
            client.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06");
            client.DefaultRequestHeaders.Remove("authorization");
            client.DefaultRequestHeaders.Add("authorization", authHeader);
            client.DefaultRequestHeaders.Add("x-ms-documentdb-isquery", "True");
            client.DefaultRequestHeaders.Add("x-ms-max-item-count", "5");
            client.DefaultRequestHeaders.Add("x-ms-continuation", string.Empty);
            var qry = new RestSqlQuery { query = "SELECT * FROM items" };
            var result = client.PostWithNoCharSetAsync(new Uri(new Uri(endpointUrl), resourceLink), qry).Result;
            var content = await result.Content.ReadAsStringAsync();
            var pagedList = JsonConvert.DeserializeObject<PagedList>(content);

            if (result.Headers.TryGetValues("x-ms-continuation", out continuationTokens))
            {
                continToken = continuationTokens.FirstOrDefault();
            }
        }
  }

Upvotes: 0

Larry Maccherone
Larry Maccherone

Reputation: 9523

You are on the right track. Two thoughts:

  1. You don't need to manually process the continuation token when using HasMoreResults and ExecuteNext. HasMoreResults checks if there is a continuation token and when you call ExecuteNext, it's automatically added.

  2. I suspect that the reason you don't see a continuation on the first round is that it's the outgoing DefaultOptions and it's not updated until it goes out again on the second ExecuteNext. I'm thinking that your output on the second loop is actually the first continuation token.

Upvotes: 1

Related Questions