<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rudi Visser</title>
    <description>The latest articles on DEV Community by Rudi Visser (@rudi_visser).</description>
    <link>https://dev.to/rudi_visser</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F11342%2Feec84112-6093-4743-819c-b797ed87b4b7.png</url>
      <title>DEV Community: Rudi Visser</title>
      <link>https://dev.to/rudi_visser</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rudi_visser"/>
    <language>en</language>
    <item>
      <title>Super Efficiently Reading Multiple Document Types from Cosmos DB (.NET SDK) - Part 2</title>
      <dc:creator>Rudi Visser</dc:creator>
      <pubDate>Thu, 27 Apr 2023 19:00:00 +0000</pubDate>
      <link>https://dev.to/rudi_visser/super-efficiently-reading-multiple-document-types-from-cosmos-db-net-sdk-part-2-1hpk</link>
      <guid>https://dev.to/rudi_visser/super-efficiently-reading-multiple-document-types-from-cosmos-db-net-sdk-part-2-1hpk</guid>
      <description>&lt;p&gt;About a week ago I wrote an article off the back of a code review about &lt;a href="https://vissers.page/articles/rudi/cosmos-net-sdk-multiple-doc-types/"&gt;how to efficiently read multiple document types from Cosmos DB&lt;/a&gt; which focused on using &lt;code&gt;GetItemQueryIterator&lt;/code&gt; which is probably the most typical use case.&lt;/p&gt;

&lt;p&gt;With that said the end result wasn't quite the one we ended up using.&lt;/p&gt;

&lt;p&gt;I spent a little time looking in to it further specifically how we could get more raw results from Cosmos. Basically, the way to get raw results from Cosmos is by using &lt;code&gt;GetItemQueryStreamIterator&lt;/code&gt; instead of &lt;code&gt;GetItemQueryIterator&lt;/code&gt;. This skips the built in serialisation using Newtonsoft.Json and lets us do whatever we want directly with the underlying ResponseMessage (and in turn the Stream).&lt;/p&gt;

&lt;p&gt;Rather than just looking at how we can use that though I upped the stakes a little on the benchmarks. First off, I've included a live benchmark which disregards the time taken as it's reliant on my network connection, but also increased the amount of documents to 41 which reflects our production workload a bit more whilst still being pretty small in the grand scheme of Cosmos.&lt;/p&gt;

&lt;p&gt;Let's first look at 2 items, the baseline from the StackOverflow answers (that is calling &lt;code&gt;ToString()&lt;/code&gt; and using &lt;code&gt;Deserialize&amp;lt;T&amp;gt;()&lt;/code&gt;), and the end result that we finished with in the last article which just directly used &lt;code&gt;.ToObject&amp;lt;T&amp;gt;()&lt;/code&gt; from the &lt;code&gt;JObject&lt;/code&gt;. Just for simplicity I've only ran this on .NET 7 as the differences between frameworks mean nothing to the end result.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline_DeserializeFromToString&lt;/td&gt;
&lt;td&gt;893.7 us&lt;/td&gt;
&lt;td&gt;17.71 us&lt;/td&gt;
&lt;td&gt;34.55 us&lt;/td&gt;
&lt;td&gt;479.07 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final_JObjectToObject&lt;/td&gt;
&lt;td&gt;366.7 us&lt;/td&gt;
&lt;td&gt;7.34 us&lt;/td&gt;
&lt;td&gt;12.26 us&lt;/td&gt;
&lt;td&gt;55.77 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These differences are as I explained in the last article and obviously show when there's more documents involved, skipping the extra steps involved in going back and forth from JSON bring excellent benefits. Frankly, for the simplicity of the code I wouldn't really recommend more than this for most scenarios.&lt;/p&gt;

&lt;p&gt;As I said above to make this more than just a benchmarking post let's take a look at the real world now and include the overhead from the Cosmos DB SDK. These are marked as _Live in the below table. Also, there's a Cosmos_Baseline thrown in there that is literally fetching the results but doing no conversion.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline_DeserializeFromToString&lt;/td&gt;
&lt;td&gt;893.7 us&lt;/td&gt;
&lt;td&gt;17.71 us&lt;/td&gt;
&lt;td&gt;34.55 us&lt;/td&gt;
&lt;td&gt;479.07 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Baseline_Live_DeserializeFromToString&lt;/td&gt;
&lt;td&gt;16,451.4 us&lt;/td&gt;
&lt;td&gt;550.98 us&lt;/td&gt;
&lt;td&gt;1,517.56 us&lt;/td&gt;
&lt;td&gt;1198.91 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline   *&lt;/td&gt;
&lt;td&gt;20.24 ms&lt;/td&gt;
&lt;td&gt;3.399 ms&lt;/td&gt;
&lt;td&gt;9.418 ms&lt;/td&gt;
&lt;td&gt;742.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final_JObjectToObject&lt;/td&gt;
&lt;td&gt;366.7 us&lt;/td&gt;
&lt;td&gt;7.34 us&lt;/td&gt;
&lt;td&gt;12.26 us&lt;/td&gt;
&lt;td&gt;55.77 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final_Live_JObjectToObject&lt;/td&gt;
&lt;td&gt;16,204.7 us&lt;/td&gt;
&lt;td&gt;422.05 us&lt;/td&gt;
&lt;td&gt;1,224.45 us&lt;/td&gt;
&lt;td&gt;775.51 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Obviously with these we can't really pay attention to the time taken as it's including a real connection and stream back of the data from Cosmos DB. However we do note that with a baseline of 743KB the final version is &lt;em&gt;actually&lt;/em&gt; only producing an additional 33KB of usage which I believe is the size of the 41 documents that we have in the database. Sweet!&lt;/p&gt;

&lt;p&gt;As a recap these tests are using &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.container.getitemqueryiterator?view=azure-dotnet"&gt;&lt;code&gt;container.GetItemQueryIterator&amp;lt;JObject&amp;gt;&lt;/code&gt;&lt;/a&gt;, here's the code for Final_Live_JObjectToObject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt; &lt;span class="n"&gt;t1Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;SecondType&lt;/span&gt; &lt;span class="n"&gt;t2Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;feedIterator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetItemQueryIterator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;queryDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequestOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasMoreResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadNextAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SecondType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SecondType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ridiculously simple and gets the job done, but we should be able to do better.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.cosmos.container.getitemquerystreamiterator?view=azure-dotnet"&gt;&lt;code&gt;GetItemQueryStreamIterator&lt;/code&gt;&lt;/a&gt;. This method differs from the non-stream version in 2 ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It skips the deserialization of the individual documents and gives us the raw result stream from the request&lt;/li&gt;
&lt;li&gt;It can only be used on single-partition queries (which, please, make sure you're doing as often as possible!)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's re-run a quick baseline for the Cosmos SDK to compare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline&lt;/td&gt;
&lt;td&gt;20.24 ms&lt;/td&gt;
&lt;td&gt;3.399 ms&lt;/td&gt;
&lt;td&gt;9.418 ms&lt;/td&gt;
&lt;td&gt;742.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline_Stream&lt;/td&gt;
&lt;td&gt;15.42 ms&lt;/td&gt;
&lt;td&gt;0.364 ms&lt;/td&gt;
&lt;td&gt;1.028 ms&lt;/td&gt;
&lt;td&gt;233.63 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Given that there's no deserialization happening with Newtonsoft.Json the memory allocated is much lower. I'm not going to spend any time investigating where that 233KB came from, let's just take it as gospel and move on to how we can now deal with it.&lt;/p&gt;

&lt;p&gt;BUT WAIT! I can hear people screaming, why not just use System.Text.Json directly with Cosmos?&lt;/p&gt;

&lt;p&gt;Unsurprisingly enough, that's essentially the answer.&lt;/p&gt;

&lt;p&gt;There's a very simple way to do this, within the GitHub Cosmos SDK repo there's a &lt;a href="https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/SystemTextJson/CosmosSystemTextJsonSerializer.cs"&gt;&lt;code&gt;CosmosSystemTextJsonSerializer.cs&lt;/code&gt;&lt;/a&gt;. Drag that in to your project, wire it up how you like (you always need to provide the options):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CosmosClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CosmosClientOptions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Serializer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CosmosSystemTextJsonSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSerializerOptions&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;PropertyNamingPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonNamingPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CamelCase&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Now we've basically cut the memory usage by half, let's take a look:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline&lt;/td&gt;
&lt;td&gt;20.24 ms&lt;/td&gt;
&lt;td&gt;3.399 ms&lt;/td&gt;
&lt;td&gt;9.418 ms&lt;/td&gt;
&lt;td&gt;742.98 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline_Stream&lt;/td&gt;
&lt;td&gt;15.42 ms&lt;/td&gt;
&lt;td&gt;0.364 ms&lt;/td&gt;
&lt;td&gt;1.028 ms&lt;/td&gt;
&lt;td&gt;233.63 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos_Baseline_STM&lt;/td&gt;
&lt;td&gt;15.82 ms&lt;/td&gt;
&lt;td&gt;0.374 ms&lt;/td&gt;
&lt;td&gt;1.074 ms&lt;/td&gt;
&lt;td&gt;421.88 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live_JsonNode_STM&lt;/td&gt;
&lt;td&gt;15.51 ms&lt;/td&gt;
&lt;td&gt;0.343 ms&lt;/td&gt;
&lt;td&gt;0.957 ms&lt;/td&gt;
&lt;td&gt;690.28 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To do this you should stop using &lt;code&gt;JObject&lt;/code&gt; and instead use &lt;code&gt;JsonNode&lt;/code&gt; (basically the System.Text.Json equivalent), also &lt;code&gt;ToObject&amp;lt;T&amp;gt;&lt;/code&gt; is &lt;code&gt;Deserialize&amp;lt;T&amp;gt;&lt;/code&gt;. The code looks like this now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;feedIterator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetItemQueryIterator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsonNode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;queryDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequestOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasMoreResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadNextAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SecondType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SecondType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usually I'd say we're done but let's get every little KB of memory out as we can (or more accurately, what I can be bothered to do).&lt;/p&gt;

&lt;p&gt;I'm not going to bang on about what's different as it should be fairly obvious by now. Using the Stream, we can simply let System.Text.Json deserialize it directly from the stream and skip a little more memory being consumed on each iteration.&lt;/p&gt;

&lt;p&gt;That looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetItemQueryStreamIterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequestOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasMoreResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResponseMessage&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;feedIterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadNextAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Documents"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;AsArray&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"core"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FirstType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"pricing_rule"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SecondType&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the change back to &lt;code&gt;GetItemQueryStreamIterator&lt;/code&gt; and now we call &lt;code&gt;JsonNode.Parse&lt;/code&gt; directly on the response stream. We're actually getting back a Cosmos result set here with the results themselves within the &lt;code&gt;Documents&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Here's the end result with another 60KB gone:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Live_JsonNode_STM&lt;/td&gt;
&lt;td&gt;15.51 ms&lt;/td&gt;
&lt;td&gt;0.343 ms&lt;/td&gt;
&lt;td&gt;0.957 ms&lt;/td&gt;
&lt;td&gt;690.28 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live_JsonNode_STM_Parsed&lt;/td&gt;
&lt;td&gt;16.40 ms&lt;/td&gt;
&lt;td&gt;0.421 ms&lt;/td&gt;
&lt;td&gt;1.196 ms&lt;/td&gt;
&lt;td&gt;631.01 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's it, possibly the most efficient way to read multiple document types from a single Cosmos container by changing 2 lines from the first article. For most implementations you shouldn't really have to bother with this at all, but if you're calling over and over and over and over and over again your servers may thank you for a little more diligence. The differences are even more apparent with more results coming out.&lt;/p&gt;

&lt;p&gt;Before I go I wanted to mention that we did try an intermediate object to map this so we could just do &lt;code&gt;.Documents&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DiscriminatorHolder&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;JsonPropertyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Documents"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsonObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Documents&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That added another 6KB so it wasn't included but it may work for you. It's still better than letting the SDK do it itself!&lt;/p&gt;

&lt;p&gt;In any case we're down from &amp;gt;1MB by relying too much on Stack Overflow, to just ~600KB for each call. That's a win.&lt;/p&gt;

&lt;p&gt;Happy Cosmosing! 🪐&lt;/p&gt;

</description>
      <category>cosmosdb</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>azure</category>
    </item>
    <item>
      <title>Efficiently Reading Multiple Document Types from Cosmos DB (.NET SDK) - From Review</title>
      <dc:creator>Rudi Visser</dc:creator>
      <pubDate>Fri, 21 Apr 2023 10:15:00 +0000</pubDate>
      <link>https://dev.to/rudi_visser/receiving-multiple-document-types-in-cosmos-db-net-sdk-from-review-36jo</link>
      <guid>https://dev.to/rudi_visser/receiving-multiple-document-types-in-cosmos-db-net-sdk-from-review-36jo</guid>
      <description>&lt;p&gt;This is a cross-post from our &lt;a href="https://vissers.page/articles/rudi/cosmos-net-sdk-multiple-doc-types/"&gt;new blog&lt;/a&gt;. Any future development-related articles will also be cross-posted here for the dev community 💪&lt;/p&gt;

&lt;p&gt;Containers, Partition Keys, Point Reads, Queries, Request Units. That's the life of Cosmos DB and it's pretty great until you need to know something.&lt;/p&gt;

&lt;p&gt;If you do end up wanting to know something specific about Cosmos DB then like every other developer you're probably going to Google it. Then you'll find yourself on Stack Overflow reading misguided questions and receiving questionable answers. Then you'll regret not being able to easily navigate Microsoft's mostly-excellent, but sometimes-lacking, documentation.&lt;/p&gt;

&lt;p&gt;Here I'll take you through a few key things to know about Cosmos DB and depending on the Google Overlords doing their job, hopefully answer a few questions that people are searching for.&lt;/p&gt;

&lt;p&gt;It's pretty long so here's a TLDR: When you're using &lt;code&gt;GetItemQueryIterator&lt;/code&gt; to read and parse documents in a single Container with multiple types, don't use &lt;code&gt;dynamic&lt;/code&gt; or &lt;code&gt;JsonConvert.DeserialiseObject()&lt;/code&gt;. It's a &lt;code&gt;JObject&lt;/code&gt; and you can simply use &lt;code&gt;ToObject&amp;lt;T&amp;gt;()&lt;/code&gt;!&lt;/p&gt;




&lt;p&gt;A little backstory first as to what prompted this article. At &lt;em&gt;[insert our next venture name]&lt;/em&gt; we use Cosmos for some parts of our architecture that heavily benefits from NoSQL and efficient operations including but not limited to auditing, configurations, highly available internal services, event streams and basic key-value type storage requirements.&lt;/p&gt;

&lt;p&gt;Late last night I was reviewing a critical path in one of our services that uses Cosmos as a backing store and noticed that it had actually undergone several fundamental changes to how it worked in the last couple of weeks. This code was storing and receiving multiple different types of documents in a single Container (which is a perfectly valid, if not encouraged practice).&lt;/p&gt;

&lt;p&gt;The code was responsible for reading different document types from a Container in Cosmos and correctly getting them to their actual types.&lt;/p&gt;

&lt;p&gt;Here's what the different versions were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Only get a single item at a time with the defined up front. Simple, effective, fast, strongly typed. This used &lt;code&gt;ReadItemAsync&amp;lt;T&amp;gt;&lt;/code&gt; from the Cosmos SDK.&lt;/li&gt;
&lt;li&gt;Get all of the documents and return them to the API as &lt;code&gt;object&lt;/code&gt; to be serialized back to JSON. This uses a Query Iterator with a query like &lt;code&gt;SELECT * FROM c&lt;/code&gt;, with a partition key. So do all of the next ones.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;dynamic&lt;/code&gt; and Newtonsoft's JsonConvert to Deserialize the result of &lt;code&gt;.ToString()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;dynamic&lt;/code&gt; and System.Text.Json's JsonSerializer to Deserialize the result of &lt;code&gt;.ToString()&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They're all ~acceptable~ ways of doing this yet I wasn't happy with any of them.&lt;/p&gt;

&lt;p&gt;I want to start by saying that I'm a huge fan of using &lt;code&gt;dynamic&lt;/code&gt; in only 2 scenarios. The first is to wind up colleagues and exclaim "DYNAMIC ALL THE WAY" just for fun. The second is when you truly don't have a clue what's going on and something could literally be anything and you need to be flexible, generally when communicating with third parties or other languages that aren't typed and we don't really care too much.&lt;/p&gt;

&lt;p&gt;When I saw &lt;code&gt;dynamic&lt;/code&gt; in actual production code that we're running and in a path that will be called many times per second I was a little confused and dug deeper.&lt;/p&gt;

&lt;p&gt;Let's understand where this came from. Here's 2 notable Stack Overflow questions that are doing what we're doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/66659540/handling-reads-of-cosmos-db-container-with-multiple-types"&gt;The first&lt;/a&gt; which includes a sample from Mark Brown, someone I consider to be the CosmosDB God. He doesn't generally answer with code from what I've seen, more about the theory and best practices, but this time he included some code as well as stating that using &lt;code&gt;dynamic&lt;/code&gt; in this scenario is a "typical pattern" to use.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/51346549/fetch-multiple-types-of-entities-from-cosmosdb-in-a-single-query"&gt;The second&lt;/a&gt; has answers from Iahsrah and Nick Chapsas (a pretty cool YouTube developer) which both also reference &lt;code&gt;dynamic&lt;/code&gt; as the way to go.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are more of these that all basically say the same thing, these are just the first 2 I found whilst writing.&lt;/p&gt;

&lt;p&gt;These answers both do a curious thing, take the dynamic object, check the type property on the document, and then &lt;code&gt;JsonConvert&lt;/code&gt; it to the type we want. Fair enough.&lt;/p&gt;

&lt;p&gt;But is it? Let's take a look.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here I've created a benchmark to test out different methods, there's 2 documents to test with, 1 is 1.8KB and the other is 2.1KB. Negligible. This is also tested on both .NET 6 and 7 as we use both in production depending on the environment. I ran these on an M1 Pro with 16GB RAM and a tonne of other stuff open, so YMMV.&lt;/p&gt;

&lt;p&gt;Note also that Newtonsoft.Json is the default (de)serializer for the Cosmos SDK v3. v4 which seems to never be coming (it hasn't been touched for years) does use System.Text.Json but for now we're stuck.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the benchmark code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Type1&lt;/span&gt; &lt;span class="n"&gt;t1Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Type2&lt;/span&gt; &lt;span class="n"&gt;t2Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;DynamicObjects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Gen0&lt;/th&gt;
&lt;th&gt;Gen1&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToString_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;33.63 us&lt;/td&gt;
&lt;td&gt;0.087 us&lt;/td&gt;
&lt;td&gt;0.077 us&lt;/td&gt;
&lt;td&gt;21.3623&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;43.7 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToString_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;27.36 us&lt;/td&gt;
&lt;td&gt;0.381 us&lt;/td&gt;
&lt;td&gt;0.356 us&lt;/td&gt;
&lt;td&gt;7.1106&lt;/td&gt;
&lt;td&gt;0.2441&lt;/td&gt;
&lt;td&gt;43.7 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Alright. 43.7KB memory, around 30 microseconds.&lt;/p&gt;

&lt;p&gt;Let's see how we improved it a little (this is essentially the latest version I had reviewed) by using System.Text.Json to deserialize it.&lt;/p&gt;

&lt;p&gt;New code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Type1&lt;/span&gt; &lt;span class="n"&gt;t1Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Type2&lt;/span&gt; &lt;span class="n"&gt;t2Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;DynamicObjects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Gen0&lt;/th&gt;
&lt;th&gt;Gen1&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToString_SystemTextJson_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;14.96 us&lt;/td&gt;
&lt;td&gt;0.038 us&lt;/td&gt;
&lt;td&gt;0.033 us&lt;/td&gt;
&lt;td&gt;13.4583&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;27.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToString_SystemTextJson_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;13.53 us&lt;/td&gt;
&lt;td&gt;0.130 us&lt;/td&gt;
&lt;td&gt;0.109 us&lt;/td&gt;
&lt;td&gt;4.4708&lt;/td&gt;
&lt;td&gt;0.1373&lt;/td&gt;
&lt;td&gt;27.48 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Better in every way! It's faster and allocates 42% less memory. Winning! We've beat out the Stack Overflow answers already.&lt;/p&gt;

&lt;p&gt;So that is the code that was left and committed and would have made it out in to production if I wasn't a pedant. But I am.&lt;/p&gt;

&lt;p&gt;We know that Cosmos DB itself as well as the SDK don't actually care what types we're storing up there as long as they meet some criteria (actually having a partition key is actually the only criteria, an ID will be generated, and the partition key could be that ID!), so the object itself is not actually &lt;code&gt;dynamic&lt;/code&gt;, it's &lt;em&gt;something&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; obj.GetType()
JObject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yup. Something. In V2 of the SDK, I believe this was &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.document?view=azure-dotnet"&gt;&lt;code&gt;Document&lt;/code&gt;&lt;/a&gt; as it's referenced in some other Stack Overflow answers though I haven't personally seen it used so can't comment.&lt;/p&gt;

&lt;p&gt;Let's work with that, and instead of using &lt;code&gt;dynamic&lt;/code&gt; which is the root of all evil in the performance world, supposedly. Instead of &lt;code&gt;DynamicObjects&lt;/code&gt; (which is what it says on the tin), &lt;code&gt;Objects&lt;/code&gt; is the same thing but as a JObject. They were both created using JObject.Parse (which is what Cosmos does internally), we're just typed now.&lt;/p&gt;

&lt;p&gt;This gives us a little more type safety. I say a little more because we're still going to just assume &lt;code&gt;obj["type"]&lt;/code&gt; is there and it's a string. Which is pretty safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Type1&lt;/span&gt; &lt;span class="n"&gt;t1Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Type2&lt;/span&gt; &lt;span class="n"&gt;t2Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Objects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="c1"&gt;// And the equivalent JsonConvert in another benchmark&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(and the JsonConvert equivalent for good comparative measure).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Gen0&lt;/th&gt;
&lt;th&gt;Gen1&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToString_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;34.14 us&lt;/td&gt;
&lt;td&gt;0.288 us&lt;/td&gt;
&lt;td&gt;0.240 us&lt;/td&gt;
&lt;td&gt;21.3623&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;43.63 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToString_SystemTextJson_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;15.33 us&lt;/td&gt;
&lt;td&gt;0.304 us&lt;/td&gt;
&lt;td&gt;0.338 us&lt;/td&gt;
&lt;td&gt;13.4277&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;27.41 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToString_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;27.39 us&lt;/td&gt;
&lt;td&gt;0.424 us&lt;/td&gt;
&lt;td&gt;0.397 us&lt;/td&gt;
&lt;td&gt;7.1106&lt;/td&gt;
&lt;td&gt;0.2136&lt;/td&gt;
&lt;td&gt;43.63 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToString_SystemTextJson_Deserialize&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;13.02 us&lt;/td&gt;
&lt;td&gt;0.254 us&lt;/td&gt;
&lt;td&gt;0.250 us&lt;/td&gt;
&lt;td&gt;4.4708&lt;/td&gt;
&lt;td&gt;0.1221&lt;/td&gt;
&lt;td&gt;27.41 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Excellent, we've shaved off a few bytes on memory allocation. Done! We have type-safety(ish, kinda, sorta) from using &lt;code&gt;JObject&lt;/code&gt; and we shaved off some time.&lt;/p&gt;

&lt;p&gt;I'm joking, obviously. Let's look at what a &lt;a href="https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jobject.htm"&gt;&lt;code&gt;JObject&lt;/code&gt; actually is&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Represents a JSON object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Helpful.&lt;/p&gt;

&lt;p&gt;Anyway to save a rant, it's basically a parsed object representing the document that was in it.&lt;/p&gt;

&lt;p&gt;Does it actually hold the original document JSON though which ToString() is just returning? Of course not, why would it? Let's see where our allocations are actually coming from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Gen0&lt;/th&gt;
&lt;th&gt;Gen1&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JObject_ToString&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;9.795 us&lt;/td&gt;
&lt;td&gt;0.0190 us&lt;/td&gt;
&lt;td&gt;0.0159 us&lt;/td&gt;
&lt;td&gt;13.3209&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;27.23 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_ToString&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;8.681 us&lt;/td&gt;
&lt;td&gt;0.1725 us&lt;/td&gt;
&lt;td&gt;0.2634 us&lt;/td&gt;
&lt;td&gt;4.4403&lt;/td&gt;
&lt;td&gt;0.0916&lt;/td&gt;
&lt;td&gt;27.23 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When we're calling JObject.ToString() we are &lt;em&gt;reserializing&lt;/em&gt; the object back to JSON. In effect, this is what the answers to the Stack Overflow questions are doing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let Cosmos load the document blob from the database itself&lt;/li&gt;
&lt;li&gt;Let Newtonsoft.Json Deserialize it from JSON to a JObject&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;.ToString()&lt;/code&gt;, serialize it back from a JObject to JSON&lt;/li&gt;
&lt;li&gt;Deserialize it (using Newtonsoft or in our case, System.Text.Json) back to our type&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We got the same JSON twice in this case, and parsed it twice too resulting in &lt;em&gt;all&lt;/em&gt; the allocations.&lt;/p&gt;

&lt;p&gt;We also learned that System.Text.Json is actually super awesome, resulting in virtually no extra allocations above the &lt;code&gt;.ToString()&lt;/code&gt;. Of course Newtonsoft.Json basically doubles it, but we knew that it was nowhere near in competition with System.Text.Json for simple document (de)serialization anyway.&lt;/p&gt;

&lt;p&gt;With that said, to use System.Text.Json we still have to call this .ToString() method. There has to be a better way!&lt;/p&gt;

&lt;p&gt;Well there is, since a &lt;code&gt;JObject&lt;/code&gt; is also a &lt;code&gt;JToken&lt;/code&gt;, it means we can access &lt;a href="https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JToken_ToObject.htm"&gt;&lt;code&gt;ToObject&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;. We'll live in the Newtonsoft.Json world still, but we're already there anyway.&lt;/p&gt;

&lt;p&gt;So here we go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Type1&lt;/span&gt; &lt;span class="n"&gt;t1Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Type2&lt;/span&gt; &lt;span class="n"&gt;t2Out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Objects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// or type = (string)obj["type"]&lt;/span&gt;
    &lt;span class="c1"&gt;// or type = obj["type"].Value&amp;lt;string&amp;gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// it doesn't matter&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t1Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"type_2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t2Out&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;th&gt;Gen0&lt;/th&gt;
&lt;th&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToObject&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;16.36 us&lt;/td&gt;
&lt;td&gt;0.046 us&lt;/td&gt;
&lt;td&gt;0.043 us&lt;/td&gt;
&lt;td&gt;1.6174&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_ToString_ToObject&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;16.22 us&lt;/td&gt;
&lt;td&gt;0.082 us&lt;/td&gt;
&lt;td&gt;0.072 us&lt;/td&gt;
&lt;td&gt;1.6174&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Value_ToObject&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;16.42 us&lt;/td&gt;
&lt;td&gt;0.051 us&lt;/td&gt;
&lt;td&gt;0.048 us&lt;/td&gt;
&lt;td&gt;1.6174&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToObject&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;.NET 6.0&lt;/td&gt;
&lt;td&gt;16.80 us&lt;/td&gt;
&lt;td&gt;0.019 us&lt;/td&gt;
&lt;td&gt;0.017 us&lt;/td&gt;
&lt;td&gt;1.6479&lt;/td&gt;
&lt;td&gt;3.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Cast_ToObject&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;12.52 us&lt;/td&gt;
&lt;td&gt;0.030 us&lt;/td&gt;
&lt;td&gt;0.027 us&lt;/td&gt;
&lt;td&gt;0.5341&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_ToString_ToObject&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;12.03 us&lt;/td&gt;
&lt;td&gt;0.018 us&lt;/td&gt;
&lt;td&gt;0.015 us&lt;/td&gt;
&lt;td&gt;0.5341&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JObject_Value_ToObject&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;11.86 us&lt;/td&gt;
&lt;td&gt;0.016 us&lt;/td&gt;
&lt;td&gt;0.015 us&lt;/td&gt;
&lt;td&gt;0.5341&lt;/td&gt;
&lt;td&gt;3.32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic_ToObject&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;.NET 7.0&lt;/td&gt;
&lt;td&gt;12.33 us&lt;/td&gt;
&lt;td&gt;0.034 us&lt;/td&gt;
&lt;td&gt;0.031 us&lt;/td&gt;
&lt;td&gt;0.5493&lt;/td&gt;
&lt;td&gt;3.39 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Consistent results, no unnecessary (de)serializing and it's just as fast as (well, slightly faster than, of course) using System.Text.Json to parse it back. The times are all so close to one another that it doesn't matter much, but the memory allocations are significant enough to make a difference when we're calling this code over and over again in quick succession.&lt;/p&gt;

&lt;p&gt;For good measure I also through the &lt;code&gt;dynamic&lt;/code&gt; benchmark back in just calling &lt;code&gt;ToObject&amp;lt;T&amp;gt;()&lt;/code&gt; with also negligible differences, but why use it when we know what it is?&lt;/p&gt;

&lt;p&gt;So there we have it. Rather than calling &lt;code&gt;.ToString()&lt;/code&gt; (serialize) and then deserializing the result from, we simply let much less of the work be done and simply map it to our target type.&lt;/p&gt;

&lt;p&gt;Also &lt;code&gt;dynamic&lt;/code&gt; is not actually that evil in this case (though it's still more evil than being explicit).&lt;/p&gt;

&lt;p&gt;There's actually an even better way to do this (that we ended up implementing), but I'll save that for a quick follow up in a couple of days once I've had chance to do real benchmarks.&lt;/p&gt;




&lt;p&gt;A small bonus for any of you that are still here and are eagle eyed enough to realise that we did a Point Read in Cosmos on the type rather than using the query to get back all of the documents. By using Point Reads we would have the strong type from the start and arguably slightly simpler code.&lt;/p&gt;

&lt;p&gt;Cosmos DB bills on Request Units (or RUs). Roughly, point reading 1 x 1KB document is 1 RU. 1 x 100KB document is 100 RU. Queries activate the Query Engine at the Cosmos Side and have a base cost of around 2.8 RU.&lt;/p&gt;

&lt;p&gt;Let's say we had 4 document types that we wanted to read, each at roughly 2KB, we can assume that a Point Read would cost us 2RU x 4 = 8 RU. Point Reads are super quick, and we see them returning in around 8ms generally which is astonishing. With that we're using 8 RU and spending around 32ms loading in the documents from Cosmos inclusive of the parsing to load in these 4 documents.&lt;/p&gt;

&lt;p&gt;However, we're only loading in 4 documents and an important thing to know is that strangely query-based RUs don't scale with document size. This seems bad for Azure's bottom line, but great for us!&lt;/p&gt;

&lt;p&gt;When running &lt;code&gt;SELECT * FROM c&lt;/code&gt; and returning those 4 documents, the query costs 2.93 RU and takes 22ms. We're slashing costs in half, and time by a third.&lt;/p&gt;

&lt;p&gt;If you have a similar set up to this give it a try if you're not already querying. Just make sure that you specify the Partition Key for the query as you don't want any cross partition queries going on.&lt;/p&gt;

&lt;p&gt;For your reference it'll look a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;QueryDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT * FROM c"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetItemQueryIterator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequestOptions&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partitionKey&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy Cosmosing and stay tuned for the even better way! 🪐&lt;/p&gt;

</description>
      <category>cosmos</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>azure</category>
    </item>
  </channel>
</rss>
