GetItemQueryStreamIterator API Name, Casing, and Sample Issues
See original GitHub issueFollowing the docs here: https://docs.microsoft.com/en-us/dotnet/api/azure.cosmos.cosmoscontainer.getitemquerystreamiterator?view=azure-dotnet-preview
I was expecting this code:
public class ToDoActivity{
public string id {get; set;}
public string status {get; set;}
public int cost {get; set;}
}
QueryDefinition queryDefinition = new QueryDefinition("select * from ToDos t where t.cost > @expensive")
.WithParameter("@expensive", 9000);
await foreach(Response response in this.Container.GetItemQueryStreamIterator(
queryDefinition,
null,
new QueryRequestOptions() { PartitionKey = new PartitionKey("Error")}))
{
using (StreamReader sr = new StreamReader(response.Content))
using (JsonTextReader jtr = new JsonTextReader(sr))
{
JObject result = JObject.Load(jtr);
}
}
To return each Document inside of the await foreach loop.
But, it actually returns a structure like this:
{
"Documents": []
}
So, I had to create a class like this:
public class QueryStream
{
[JsonPropertyName("Documents")]
public QueueMessage[] Documents { get; set; }
}
And then deserialize using that class.
Issue # 1: “Documents” casing
Because “Documents” is Pascal casing it will conflict with my SerializationOptions and child documents, which have camelCasing.
Question: Should we use “documents” instead or enable the user to specify casing for the outer documents. Or ask users to name their property “public QueueMessage[] documents” so the casing is honor. As you can see above I needed to add a JsonPropertyNames attribute, because I’m deserializing with camel and so it expects Documents to be camel as well.
Issue # 2: API name
Based on the example and the API name, I was expecting it to yield for every document, not every page.
Question: Should this be renamed to GetItemPageQueryStreamIterator?
Issue # 3: Docs are misleading.
Because the doc has a single item class ToDoActivity, I was led to believe it would return individual items.
Suggestion: Update the sample to make it very clear what the dev has to do to use it.
Here’s the code to get this working…this included a lot of trial and error and debugging to figure out.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Azure;
using Azure.Cosmos;
using Azure.Cosmos.Serialization;
using DotNetEnv;
namespace cosmostest
{
public class QueryStream
{
[JsonPropertyName("Documents")]
public QueueMessage[] Documents { get; set; }
}
class Program
{
static async Task Main(string[] args)
{
Env.Load();
CosmosClientOptions options = new CosmosClientOptions
{
SerializerOptions = new CosmosSerializationOptions { PropertyNamingPolicy = CosmosPropertyNamingPolicy.Default }
};
CosmosClient cosmosClient = new CosmosClient(
Environment.GetEnvironmentVariable("AZURE_COSMOS_ENDPOINT"),
Environment.GetEnvironmentVariable("AZURE_COSMOS_KEY"), options);
CosmosContainer cosmosContainer = cosmosClient.GetDatabase(Environment.GetEnvironmentVariable("AZURE_COSMOS_DB")).GetContainer(Environment.GetEnvironmentVariable("AZURE_COSMOS_CONTAINER"));
QueryDefinition queryDefinition = new QueryDefinition("SELECT * FROM c");
List<QueueMessage> msgs = new List<QueueMessage>();
await foreach (Response response in cosmosContainer.GetItemQueryStreamIterator(queryDefinition))
{
var queryStream = await JsonSerializer.DeserializeAsync<QueryStream>(response.ContentStream,
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
msgs.AddRange(queryStream.Documents);
}
}
}
}
azsdke2e
Issue Analytics
- State:
- Created 3 years ago
- Comments:16 (15 by maintainers)
Top GitHub Comments
This API was really not intuitive. The
GetItemQueryStreamIterator
returning a document with theDocuments
property that’s the actual collection of the items is very confusing.@SeanFeldman That is part of the REST API contract. It is not part of the SDK definition nor a contract defined by the SDK, so there is nothing that can be done on the SDK to remove that property, because that is the server response as defined in https://docs.microsoft.com/en-us/rest/api/cosmos-db/query-documents#body-1.
If you are deserializing the Stream (this thread is for the Stream APIs) you could lookup that property to initialize the array/list that contains your results to avoid memory resizing if you wished, not really required, but it’s one usage I can think of.