Azure CosmosDB Essentials: A Step-by-Step Tutorial


What is Azure CosmosDB?
Azure CosmosDB is a globally distributed, multi-model database service provided by Microsoft Azure. It is designed to offer high availability, low latency, and scalability for applications that require a distributed database system. With Azure CosmosDB, you can store and manage data in various formats, including document, key-value, graph, and column-family data models.
In this article, you have detailed the steps to create an Azure Cosmos DB account, set up a storage account, upload images to Azure Blob Storage, and manage JSON data. This process involves creating resources in the Azure portal, configuring settings, and using Visual Studio Code to handle JSON data uploads to Cosmos DB. The article also covers validating the data upload by querying the Cosmos DB database.
Architecture Diagram
Creating data store resources in Azure
Create an Azure Cosmos DB account resource
Browse to the Azure portal at https://portal.azure.com
, and then sign in with your account.
In the Azure portal, select Azure Cosmos DB. On the Azure Cosmos DB blade, select + Create
Select Create in the Azure Cosmos DB for NoSQL box.
Details (account name: ptcgp-data)
Setting | Action |
Subscription | Retain defaults |
Resource group | Create new resource group named ptcgp-rg |
Account Name | Enter ptcgp-data |
Location | (US) East US |
Capacity mode | Select Serverless |
On the Review + create tab of the Create Azure Cosmos DB Account - Azure Cosmos DB for NoSQL page, review the options and select Create to create the Azure Cosmos DB account by using your specified configuration.
Once create, select Go to resource to access the Azure Cosmos DB Account.
On the Azure Cosmos DB account blade, find the Settings section, and then select the Keys link.
In the Keys pane, on the Read-write Keys tab, record the values of the URI, PRIMARY KEY, and PRIMARY CONNECTION STRING text boxes. These values will be used later.
URI:
https://ptcgp-data.documents.azure.com:443/
PRIMARY KEY:
Aovs4GRctGIKEIGmEd6kkzoUcP8lW4WKWQgvokv9jZgJxYhuVavUgBr82juOGhQjdKKk1avNbJx5ACDbv2ls2w==
CONNECTION STRING:
AccountEndpoint=
https://ptcgp-data.documents.azure.com:443/;AccountKey=Aovs4GRctGIKEIGmEd6kkzoUcP8lW4WKWQgvokv9jZgJxYhuVavUgBr82juOGhQjdKKk1avNbJx5ACDbv2ls2w==
;
Create an Azure Storage account resource
In the Azure portal, select Storage accounts. On the Storage accounts blade, select + Create.
On the Basics tab of the Create a storage account blade, perform the following actions, and then select Review + Create:
Setting | Action |
Subscription | Retain defaults |
Resource group | Select ptcgp-rg |
Storage account name | enter ptcgpstorage |
Region | US East US (same region where you created the Cosmos DB account earlier) |
Primary service | No changes |
Performance | Select Standard |
Redundancy | Select Locally-redundant storage (LRS) |
Review the options that you selected during the previous steps and select Create to create the storage account by using your specified configuration.
Uploading and Managing Images in Azure Blob Storage
Download images from Limitless website:
Save the images into Donwloads directory and rename them setting the name all to lowercase: a1_033_en.webp
, a1_034_en.webp
…
On the ptcgpstorage storage account blade, select the Containers link in the Data storage section.
In the Containers section, select + Container. In the New container pop-up window, perform the following actions, and then select Create:
Setting | Action |
Name | Enter images |
Find the Settings section on the Container blade, and then select the Properties link.
- URL:
https://ptcgpstorage.blob.core.windows.net/images
Click on Shared access tokens next and generate an access token with the default settings by clicking Generate SAS token and URL. Record the value of the Blob SAS token into Notepad, you will need this later.
Blob SAS token:
sp=r&st=2025-07-14T10:02:14Z&se=2025-07-21T18:17:14Z&spr=https&sv=2024-11-04&sr=c&sig=ZcptOw3MPqSYpqspB7dEyLaZKtSD5bqN%2FW6gzwmK0B0%3D
Blob SAS URL:
https://ptcgpstorage.blob.core.windows.net/images?sp=r&st=2025-06-03T14:47:04Z&se=2025-06-03T22:47:04Z&spr=https&sv=2024-11-04&sr=c&sig=FqEr9jfhioBRzhrizFLjmouLyHeIZkcTsePFUsh7OY8%3D
On the blade, select Upload. In the Upload blob pop-up, perform the following actions:
In the Files section, select Browse for files or use the drag and drop feature.
In the File Explorer window, browse to Downloads, select all the 7 image files, and then select Open.
Ensure that Overwrite if files already exist is selected, and then select Upload.
Review JSON data
From the lab computer, start Visual Studio Code.
From the File menu, select Open File, browse to ptcgp-db/PTCGPocket.Upload/cards.json, select cards.json, and then select Open.
Review the format of the cards.json file and note that it contains an array of JSON objects.
[
{
"id":"A1-033",
"Name":"Charmander",
"HP":"60",
"Type":"Fire",
"CardType":"Pokémon - Basic",
"EvolutionType":"Basic",
"Image":"a1_033_en.webp",
"Weakness":"Water",
"Retreat":"1",
"Rarity":"◊",
"FullArt":"No",
"EX":"No",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"Teeziro",
"CraftingCost":35
},
{
"id":"A1-034",
"Name":"Charmeleon",
"HP":"90",
"Type":"Fire",
"CardType":"Pokémon - Stage 1 - Evolves from Charmander",
"EvolutionType":"Stage 1",
"Image":"a1_034_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"◊◊",
"FullArt":"No",
"EX":"No",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"kantaro",
"CraftingCost":70
},
{
"id":"A1-035",
"Name":"Charizard",
"HP":"150",
"Type":"Fire",
"CardType":"Pokémon - Stage 2 - Evolves from Charmeleon",
"EvolutionType":"Stage 2",
"Image":"a1_035_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"◊◊◊",
"FullArt":"No",
"EX":"No",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"takuyoa",
"CraftingCost":150
},
{
"id":"A1-036",
"Name":"Charizard ex",
"HP":"180",
"Type":"Fire",
"CardType":"Pokémon - Stage 2 - Evolves from Charmeleon",
"EvolutionType":"Stage 2",
"Image":"a1_036_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"◊◊◊◊",
"FullArt":"No",
"EX":"Yes",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"PLANETA Mochizuki",
"CraftingCost":500
},
{
"id":"A1-253",
"Name":"Charizard ex",
"HP":"180",
"Type":"Fire",
"CardType":"Pokémon - Stage 2 - Evolves from Charmeleon",
"EvolutionType":"Stage 2",
"Image":"a1_253_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"☆☆",
"FullArt":"Yes",
"EX":"Yes",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"PLANETA CG Works",
"CraftingCost":1250
},
{
"id":"A1-280",
"Name":"Charizard ex",
"HP":"180",
"Type":"Fire",
"CardType":"Pokémon - Stage 2 - Evolves from Charmeleon",
"EvolutionType":"Stage 2",
"Image":"a1_280_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"☆☆☆",
"FullArt":"Yes",
"EX":"Yes",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Charizard pack",
"Artist":"kantaro",
"CraftingCost":1500
},
{
"id":"A1-284",
"Name":"Charizard ex",
"HP":"180",
"Type":"Fire",
"CardType":"Pokémon - Stage 2 - Evolves from Charmeleon",
"EvolutionType":"Stage 2",
"Image":"a1_284_en.webp",
"Weakness":"Water",
"Retreat":"2",
"Rarity":"Crown Rare",
"FullArt":"Yes",
"EX":"Yes",
"Set":"A1",
"SetDetails":"Genetic Apex (A1)",
"Pack":"Every pack",
"Artist":"PLANETA CG Works",
"CraftingCost":0
}
]
Create a Cosmos DB database and collection, and perform a JSON data upload
In the File Explorer window that opens, browse to ptcgp-db, and then select Select Folder.
In the Visual Studio Code window, on the Menu Bar, select Terminal and then select New Terminal.
Add the Azure Cosmos DB .NET client library to the currently opened project
dotnet add package Microsoft.Azure.Cosmos --version 3.28.0
PS C:\ptcgp-db> cd .\PTCGPocket.Upload\
PS C:\ptcgp-db\PTCGPocket.Upload> dotnet add package Microsoft.Azure.Cosmos --version 3.28.0
Determining projects to restore...
Writing C:\Users\Admin\AppData\Local\Temp\tmpm45xp3.tmp
info : X.509 certificate chain validation will use the default trust store selected by .NET for code signing.
info : X.509 certificate chain validation will use the default trust store selected by .NET for timestamping.
info : Adding PackageReference for package 'Microsoft.Azure.Cosmos' into project 'C:\ptcgp-db\PTCGPocket.Upload\PTCGPocket.Upload.csproj'.
info : Restoring packages for C:\ptcgp-db\PTCGPocket.Upload\PTCGPocket.Upload.csproj...
info : GET https://api.nuget.org/v3-flatcontainer/microsoft.azure.cosmos/index.json
# --- TRUNCATED OUTPUT ---
info : OK https://api.nuget.org/v3-vulnerabilities/2025.05.28.05.39.59/2025.06.03.11.40.28/vulnerability.update.json 105ms
info : Package 'Microsoft.Azure.Cosmos' is compatible with all the specified frameworks in project 'C:\ptcgp-db\PTCGPocket.Upload\PTCGPocket.Upload.csproj'.
info : PackageReference for package 'Microsoft.Azure.Cosmos' version '3.28.0' updated in file 'C:\ptcgp-db\PTCGPocket.Upload\PTCGPocket.Upload.csproj'.
info : Generating MSBuild file C:\ptcgp-db\PTCGPocket.Upload\obj\PTCGPocket.Upload.csproj.nuget.g.props.
info : Generating MSBuild file C:\ptcgp-db\PTCGPocket.Upload\obj\PTCGPocket.Upload.csproj.nuget.g.targets.
info : Writing assets file to disk. Path: C:\ptcgp-db\PTCGPocket.Upload\obj\project.assets.json
log : Restored C:\ptcgp-db\PTCGPocket.Upload\PTCGPocket.Upload.csproj (in 18.37 sec).
In the Explorer pane of the Visual Studio Code window, expand the PTCGPocket.Upload project.
Open the Program.cs file.
On the line 16, set the value of EndpointUrl by replacing the empty string with the URI property of the Cosmos DB account that you recorded earlier in this lab. Ensure that the value is enclosed in double quotes. This is the first value you recorded in Notepad.
On the line 17, set the value of AuthorizationKey by replacing the empty string with the PRIMARY KEY property of the Cosmos DB account that you recorded earlier in this lab. Ensure that the value is enclosed in double quotes. This is the second value you recorded in Notepad.
On the line 20, set the value of PartitionKey by replacing the empty string with
/Rarity
namespace PTCGPocket.Upload
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Text.Json;
using System.IO;
using Microsoft.Azure.Cosmos;
public class Program
{
private const string EndpointUrl = "https://ptcgp-data.documents.azure.com:443/";
private const string AuthorizationKey = "Aovs4GRctGIKEIGmEd6kkzoUcP8lW4WKWQgvokv9jZgJxYhuVavUgBr82juOGhQjdKKk1avNbJx5ACDbv2ls2w==";
private const string DatabaseName = "Cards";
private const string ContainerName = "Online";
private const string PartitionKey = "/Rarity";
private const string JsonFilePath = "C:\\ptcgp-db\\PTCGPocket.Upload\\cards.json";
Within the try block, note the invocation of the CreateDatabaseIfNotExistsAsync method of the CosmosClient class. This will create a database if one doesn't already exist.Note the invocation of the DefineContainer method of the Database class. This will create a container that will host the JSON items if one doesn't already exist.
// <CreateClient>
CosmosClient cosmosClient = new CosmosClient(EndpointUrl, AuthorizationKey, new CosmosClientOptions() { AllowBulkExecution = true });
// </CreateClient>
// <Initialize>
Console.WriteLine($"Creating a database if not already exists...");
Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync(Program.DatabaseName);
Review the Cards class (PTCGPocket.Cards/Cards.cs
) that reflect the format of the objects stored in the JSON-formatted file you reviewed earlier in this lab.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace PTCGPocket.Cards
{
public class Card
{
[Key]
public string id { get; set; }
public string Name { get; set; }
public string HP { get; set; }
public string Type { get; set; }
public string CardType { get; set; }
public string EvolutionType { get; set; }
public string Image { get; set; }
public string Weakness { get; set; }
public string Retreat { get; set; }
public string Rarity { get; set; }
public string FullArt { get; set; }
public string EX { get; set; }
public string Set { get; set; }
public string SetDetails { get; set; }
public string Pack { get; set; }
public string Artist { get; set; }
public int CraftingCost { get; set; }
}
}
In terminal, run the following command to restore any missing NuGet packages and build the project in the folder:
PS C:\ptcgp-db\PTCGPocket.Upload> dotnet build
MSBuild version 17.8.3+195e7f5a3 for .NET
Determining projects to restore...
All projects are up-to-date for restore.
PTCGPocket.Upload -> C:\ptcgp-db\PTCGPocket.Upload\bin\Debug\net8.0\PTCGPocket.Upload.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:11.96
From the terminal prompt, run the following command to run the .NET Core console application:
Observe the results of running the command printed in the terminal. The run should complete successfully, displaying the message about there being 7 items inserted into the target Cosmos DB collection.
PS C:\ptcgp-db\PTCGPocket.Upload> dotnet run
Creating a database if not already exists...
Creating a container if not already exists...
Preparing 7 items to insert...
Starting...
Inserting: {"id":"A1-033","Name":"Charmander","HP":"60","Type":"Fire","CardType":"Pok\u00E9mon - Basic","EvolutionType":"Basic","Image":"A1_033_EN.webp","Weakness":"Water","Retreat":"1","Rarity":"\u25CA","FullArt":"No","EX":"No","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"Teeziro","CraftingCost":35}
Inserting: {"id":"A1-034","Name":"Charmeleon","HP":"90","Type":"Fire","CardType":"Pok\u00E9mon - Stage 1 - Evolves from Charmander","EvolutionType":"Stage 1","Image":"A1_034_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"\u25CA\u25CA","FullArt":"No","EX":"No","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"kantaro","CraftingCost":70}
Inserting: {"id":"A1-035","Name":"Charizard","HP":"150","Type":"Fire","CardType":"Pok\u00E9mon - Stage 2 - Evolves from Charmeleon","EvolutionType":"Stage 2","Image":"A1_035_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"\u25CA\u25CA\u25CA","FullArt":"No","EX":"No","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"takuyoa","CraftingCost":150}
Inserting: {"id":"A1-036","Name":"Charizard ex","HP":"180","Type":"Fire","CardType":"Pok\u00E9mon - Stage 2 - Evolves from Charmeleon","EvolutionType":"Stage 2","Image":"A1_036_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"\u25CA\u25CA\u25CA\u25CA","FullArt":"No","EX":"Yes","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"PLANETA Mochizuki","CraftingCost":500}
Inserting: {"id":"A1-253","Name":"Charizard ex","HP":"180","Type":"Fire","CardType":"Pok\u00E9mon - Stage 2 - Evolves from Charmeleon","EvolutionType":"Stage 2","Image":"A1_253_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"\u2606\u2606","FullArt":"Yes","EX":"Yes","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"PLANETA CG Works","CraftingCost":1250}
Inserting: {"id":"A1-280","Name":"Charizard ex","HP":"180","Type":"Fire","CardType":"Pok\u00E9mon - Stage 2 - Evolves from Charmeleon","EvolutionType":"Stage 2","Image":"A1_280_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"\u2606\u2606\u2606","FullArt":"Yes","EX":"Yes","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Charizard pack","Artist":"kantaro","CraftingCost":1500}
Inserting: {"id":"A1-284","Name":"Charizard ex","HP":"180","Type":"Fire","CardType":"Pok\u00E9mon - Stage 2 - Evolves from Charmeleon","EvolutionType":"Stage 2","Image":"A1_284_EN.webp","Weakness":"Water","Retreat":"2","Rarity":"Crown Rare","FullArt":"Yes","EX":"Yes","Set":"A1","SetDetails":"Genetic Apex (A1)","Pack":"Every pack","Artist":"PLANETA CG Works","CraftingCost":0}
Finished writing 7 items in 00:00:01.2278195.
Validing Data Uploads in CosmosDB
On the Azure Cosmos DB account blade, find and select the Data Explorer link on the blade and expand the Cards
database node.
Expand the Online container node, and then select New SQL Query.
SELECT * FROM cards
Select Execute Query, and then observe the list of JSON items returned by the query.
Back in the query editor, replace the existing text with the following text:
SELECT c.id, c.Name, c.Hp, c.Rarity
FROM c
WHERE STARTSWITH(c.Name, "Charizard")
Results are filtered just showing id
, Name
and Rarity
attributes from each item.
Sources
Subscribe to my newsletter
Read articles from Daniel Benitez directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Daniel Benitez
Daniel Benitez
👋 Hi! I’m Dani, a passionate automation, Ansible, DevOps, and Cloud technologies enthusiast. I currently work as a Middleware Solutions Architect at Atradius, leading middleware automation and optimizing IT infrastructure. 💡 My Story: I started my career specializing in Oracle Middleware, working with technologies such as WebLogic, Oracle Database, Oracle iPlanet Web Server, and Oracle JDK. Over time, my focus shifted towards deployment automation, continuous integration, and process optimization in complex enterprise environments. 🚀 Impact & Achievements: ✅ Direct the automation of Oracle Fusion Middleware (FMW) with Ansible, streamlining the installation, configuration, and patching processes for Oracle WebLogic, SOA Suite, and OSB. ✅ Lead IBM WebSphere Application Server (WAS) automation with Ansible and AWX, including installation, configuration, certificates, and deployments, reducing implementation times by 70%. ✅ Integrated Azure DevOps with AWX, eliminating manual deployment tasks and reducing human intervention to a simple approval step. ✅ Mentor and train teams on Ansible automation, fostering continuous improvement and knowledge transfer. 🏀🥎 In my free time, I enjoy playing padel and basketball, always looking for new challenges and improvements, both in sports and technology. I also love building web applications with Oracle APEX, bringing ideas to life through low-code development. 📥 Let’s connect! 📧 Email: dbenitez.vk@gmail.com 🔗 LinkedIn: https://www.linkedin.com/in/danielbenitezaguila 💻 GitHub: https://github.com/dbeniteza