Azure · lesson 11 of 19
Beginner
4Intermediate
13- 5 Azure Virtual Network Basics
- 6 Azure SQL Basics
- 7 Azure Functions Fundamentals
- 8 Bicep and ARM Templates Basics
- 9 Azure Monitor Basics
- 11 Azure Cosmos DB: Items and Partition Keys
- 12 Azure Cosmos DB: Queries
- 13 Azure Cosmos DB: ETags and Patch
- 14 Azure Service Bus: Queues and Settlement
- 15 Azure Service Bus: Dead-Lettering
- 16 Azure Service Bus: Topics and Filters
- 17 Azure Key Vault: Secrets and Versions
- 18 Azure Key Vault: Soft-Delete and Recovery
Also part of Azure
5- + Dead-Letter Queues: What Happens When Retries Keep Failing from Event-Driven Architecture
- + Idempotent Consumers: Surviving a Duplicate Delivery from Event-Driven Architecture
- + Envelope Encryption and Key Rotation Without Re-encrypting Data from Cryptography
- + Deployments and Rollouts from Kubernetes
- + Services and Networking from Kubernetes
Azure Cosmos DB: Items and Partition Keys
Create a Cosmos DB container with a partition key, upsert items into it, and read one back with the Python SDK against the official vNext emulator — then see why reading with the wrong partition key 404s instead of finding the item a different way.
By SkillByExample · Published
A Cosmos DB container doesn’t have a schema, but it does have a partition key: a required property every item must carry, which Cosmos DB uses to decide where that item physically lives. This lesson runs against Microsoft’s own vNext emulator in Docker — a real local Cosmos DB, not a third-party stand-in — so everything here except RU pricing behaves the way the production service does.
Upserting Items and Reading One Back
from azure.cosmos import CosmosClient, PartitionKey
ENDPOINT = "http://localhost:8081"
KEY = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
client = CosmosClient(ENDPOINT, credential=KEY)
db = client.create_database_if_not_exists("storedb")
container = db.create_container_if_not_exists(
id="orders", partition_key=PartitionKey(path="/customer")
)
for order_id, customer, total in [("o0", "alice", 30), ("o1", "bob", 12), ("o2", "alice", 55)]:
container.upsert_item({"id": order_id, "customer": customer, "total": total})
ru = container.client_connection.last_response_headers.get("x-ms-request-charge")
print(f"upsert {order_id} RU: {ru}")
item = container.read_item(item="o0", partition_key="alice")
print("read o0 total:", item["total"])
print("read o0 has etag:", "_etag" in item)
$ docker run -d --name az-cosmos-demo -e PROTOCOL=http mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-EN20261019
30c0908bbbd64f58327f47a1743d9516006ff6c850b44e557fbf03dd03fb0be6
$ until docker logs az-cosmos-demo 2>&1 | grep -q 'System is now fully ready to accept requests'; do sleep 0.5; done
$ docker run --rm --network container:az-cosmos-demo -v "$(pwd)":/app -w /app python:3.14-slim bash -c "pip install -q azure-cosmos==4.17.1 2>&1 | tail -1 && python cosmos_items.py"
[notice] To update, run: pip install --upgrade pip
upsert o0 RU: 1
upsert o1 RU: 1
upsert o2 RU: 1
read o0 total: 30
read o0 has etag: True
The emulator reports RU: 1 for every write here, regardless of item size — that’s the one place
it diverges from the real service, which prices a request by its actual size and complexity.
read_item takes both the id and the partition_key because together they’re the full address
of one item; a container with a million items and the right partition key still costs roughly the
same as one with ten.
The Wrong Partition Key Looks Exactly Like “Not Found”
from azure.cosmos import CosmosClient, exceptions
ENDPOINT = "http://localhost:8081"
KEY = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
client = CosmosClient(ENDPOINT, credential=KEY)
container = client.get_database_client("storedb").get_container_client("orders")
try:
container.read_item(item="o0", partition_key="bob")
except exceptions.CosmosResourceNotFoundError as e:
print("read with wrong partition key ->", type(e).__name__, e.status_code)
item = container.read_item(item="o0", partition_key="alice")
print("read with correct partition key -> total:", item["total"])
$ docker run --rm --network container:az-cosmos-demo -v "$(pwd)":/app -w /app python:3.14-slim bash -c "pip install -q azure-cosmos==4.17.1 2>&1 | tail -1 && python cosmos_wrong_pk.py"
[notice] To update, run: pip install --upgrade pip
read with wrong partition key -> CosmosResourceNotFoundError 404
read with correct partition key -> total: 30
o0 really does exist — just under partition key "alice", not "bob". Cosmos DB’s point-read
API doesn’t search other partitions to tell you that; it treats “right id, wrong partition key” as
indistinguishable from “no such item”, because the partition key is part of the lookup address,
not a filter applied after finding the item. Code that doesn’t already know an item’s partition
key has to query for it instead of guessing at read_item.
Practice
1. Upsert a fourth order and overwrite one of the existing orders' total with upsert_item, then confirm the overwrite took effect.
from azure.cosmos import CosmosClient
ENDPOINT = "http://localhost:8081"
KEY = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
client = CosmosClient(ENDPOINT, credential=KEY)
container = client.get_database_client("storedb").get_container_client("orders")
container.upsert_item({"id": "o3", "customer": "carol", "total": 99})
container.upsert_item({"id": "o0", "customer": "alice", "total": 45})
print("o3 total:", container.read_item(item="o3", partition_key="carol")["total"])
print("o0 total after overwrite:", container.read_item(item="o0", partition_key="alice")["total"])
$ docker run --rm --network container:az-cosmos-demo -v "$(pwd)":/app -w /app python:3.14-slim bash -c "pip install -q azure-cosmos==4.17.1 2>&1 | tail -1 && python cosmos_overwrite.py"
[notice] To update, run: pip install --upgrade pip
o3 total: 99
o0 total after overwrite: 45
upsert_item with an id that already exists in that partition replaces the whole item — o0’s
total goes from 30 to 45, nothing merges field by field.
2. Call create_item with an id that already exists and see what exception that raises instead.
from azure.cosmos import CosmosClient, exceptions
ENDPOINT = "http://localhost:8081"
KEY = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
client = CosmosClient(ENDPOINT, credential=KEY)
container = client.get_database_client("storedb").get_container_client("orders")
try:
container.create_item({"id": "o0", "customer": "alice", "total": 1})
except exceptions.CosmosResourceExistsError as e:
print("create_item on existing id ->", type(e).__name__, e.status_code)
$ docker run --rm --network container:az-cosmos-demo -v "$(pwd)":/app -w /app python:3.14-slim bash -c "pip install -q azure-cosmos==4.17.1 2>&1 | tail -1 && python cosmos_create_conflict.py"
[notice] To update, run: pip install --upgrade pip
create_item on existing id -> CosmosResourceExistsError 409
create_item is upsert_item’s stricter sibling: same partition key rules, but a duplicate id
raises CosmosResourceExistsError (409) instead of silently overwriting.
3. Create a second container with a different partition key path and confirm the two containers' items are independent.
from azure.cosmos import CosmosClient, PartitionKey
ENDPOINT = "http://localhost:8081"
KEY = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
client = CosmosClient(ENDPOINT, credential=KEY)
db = client.get_database_client("storedb")
products = db.create_container_if_not_exists(
id="products", partition_key=PartitionKey(path="/category")
)
products.upsert_item({"id": "p0", "category": "books", "name": "Cosmos DB Guide"})
orders = db.get_container_client("orders")
print("products container item count:", len(list(products.read_all_items())))
has_o0 = any(i["id"] == "o0" for i in orders.read_all_items())
print("orders container still has o0:", has_o0)
$ docker run --rm --network container:az-cosmos-demo -v "$(pwd)":/app -w /app python:3.14-slim bash -c "pip install -q azure-cosmos==4.17.1 2>&1 | tail -1 && python cosmos_second_container.py"
[notice] To update, run: pip install --upgrade pip
products container item count: 1
orders container still has o0: True
Containers in the same database don’t share items or even partition-key schemes — products
uses /category, orders uses /customer, and neither container’s items are visible through
the other’s client.
Cleanup
$ docker rm -f az-cosmos-demo
az-cosmos-demo
Next: parameterised and aggregate queries against this same container.