Search code examples
c#azure-cosmosdb

Cosmos Continuation Token/MaxItems when querying Item sub collection


Cosmos newbie question here. I have a Container called Orders and each Order Item in the Collection has a structure like

{
   "id":"9b461e2f-3728-46f0-9383-103be9e225f9"
   "agentId":"4v587r3h-3728-46f0-9383-103be9e225f9"
   "OrderItems": [{
     "OrderItemId":"8a378g5w-3728-46f0-9383-103be9e225f9",
     "ProductId": 100, 
     "Qty": 3
   }]
}

Something like

//agencyId, continuationToken, paginationNumber came in via API call. Cosmos generated the tokens

var result = await container.GetItemLinqQueryable<Order>(continuationToken: continuationToken,
 requestOptions: new QueryRequetOptions() 
{ 
 PartitionKey = new PartitionKey("someKey"), 
 MaxItems = paginationNumber
}).Where(o => o.AgencyId == agencyId).ToFeedIterator().ToListyAsycnWithContinue();

I've seen examples that show how to query this Collection where it returns a list of the Item type, ie Orders and a continuationToken which could be exposed via an API to allow a client of that API a means to paginate results by adding the continuationToken to any future requests and Cosmos could then resume the query observing a MaxCount items.

I'd like to query this Collection to return all the OrderItems that were placed by a particular AgentId. Where does the continuationToken/maxItems values come into play here as my intent would be that they'd be referring to the OrderItems not at the Order level. So if maxItems was 20 for example, I'm saying restrict this to 20 OrderItems not 20 Orders.


Solution

  • The continuationToken isn't useful for that. It's purely for retrieving additional documents from a query and not subelements within a documents. The continuationToken is used to keep track of the state of query so you can continue from the last document in the query without logicaly iterating over all documents queried before it.

    If you want to paginate over information within a document you'll need to write a query for that yourself (e.g. having the client passing the offset and limit and using ARRAY_SLICE to retrieve the relevant OrderItems).

    Since you ideally have kept your documents small you could also opt to retrieve all OrderItems and filter client side so only one page is viewable at a time, but all are retrieved in a single request and kept in memory. Using point reads and small documents you can keep your RU usage to a minimum this way.

    Lastly you can also opt to change your structure and save each OrderItem as individual document. That'll of course have a lot of other effects on querying data. When pagination is your only issue then this likely isn't the best option.