Cosmos DB Interview Questions and Answers Part 1 - Cosmos DB Fundamentals and Architecture

Cosmos DB Interview Q&A · Part 1 of 10

In this post we are going to cover Azure Cosmos DB fundamentals and architecture. These are 7 real Cosmos DB interview questions for data engineers, asked the way they come up on a real project, and the last one is a scenario: the business wants a product catalog and shopping cart that answer in milliseconds for customers worldwide, and you design it.

Cosmos DB is Microsoft's fully managed NoSQL database for operational apps. We store JSON items in containers, Cosmos DB indexes them for us, and it scales out by a partition key. Interviewers start here because every later question builds on it: the resource model, the APIs, the system properties on every item, and how we pay for throughput. If you can also say when Cosmos DB is the wrong choice, you show that you've actually run it.

Part 1 of the Real Time Azure Cosmos DB Interview Questions and Answers series on TechBrothersIT.

The short answer

Say this first

Azure Cosmos DB is a fully managed NoSQL database: schema-agnostic JSON items in containers, automatic indexing, scale-out by partition key and global distribution. Pick the API for your code, design around point reads by id + partition key, and buy throughput as provisioned, autoscale or serverless.

Let's set up the project

We run the official Azure Cosmos DB Linux emulator locally, and small Python scripts that use the azure-cosmos client, so every output is real. Features the emulator doesn't support are shown as code. common.py connects with the COSMOS_ENDPOINT and COSMOS_KEY environment variables, creates the shop database, and has a small helper, mine(), that keeps only our own fields and drops the ones starting with an underscore.

common.py
import os
from azure.cosmos import CosmosClient

client = CosmosClient(os.environ["COSMOS_ENDPOINT"],
                      credential=os.environ["COSMOS_KEY"])
shop = client.create_database_if_not_exists("shop")


def mine(item):
    """Your own fields only: drop _rid, _etag, _ts and friends."""
    return {k: item[k] for k in sorted(item) if not k.startswith("_")}

Question 1: Your manager asks what Azure Cosmos DB is and why the team would use it instead of a relational database. What do you say?

Azure Cosmos DB is a fully managed NoSQL database for operational apps. It stores JSON items without a fixed schema, indexes every property automatically, scales out by partitioning, replicates to any Azure region you add, and offers five consistency levels.

Microsoft documents these numbers for it:

Microsoft documentsValue
Reads and writesunder 10 ms at the 99th percentile
Availability, multi-region writes99.999% for reads and writes

Now let's see the schema flexibility. flexible.py creates one products container, partitioned by /category. It writes a book with an author and pages, and headphones with colors and a nested specs object. There is no CREATE TABLE and no ALTER TABLE. Then it lists each item's keys and queries the nested field. We run python flexible.py.

flexible.py
from azure.cosmos import PartitionKey
from common import shop, mine

products = shop.create_container_if_not_exists(
    "products", partition_key=PartitionKey(path="/category"))
products.upsert_item({"id": "bk-101", "category": "books",
                      "name": "Python for Data Teams", "price": 39.5,
                      "author": "S. Malik", "pages": 320})
products.upsert_item({"id": "hp-201", "category": "audio",
                      "name": "Studio Headphones", "price": 89.9,
                      "colors": ["black", "white"],
                      "specs": {"wireless": True, "hours": 30}})
for p in products.query_items("SELECT * FROM c ORDER BY c.id",
                              enable_cross_partition_query=True):
    print(p["id"], list(mine(p)))
q = "SELECT c.id, c.specs.hours FROM c WHERE c.specs.wireless = true"
print("wireless:", list(products.query_items(
    q, enable_cross_partition_query=True)))
Terminal
$ python flexible.py
bk-101 ['author', 'category', 'id', 'name', 'pages', 'price']
hp-201 ['category', 'colors', 'id', 'name', 'price', 'specs']
wireless: [{'id': 'hp-201', 'hours': 30}]

Each item keeps its own shape. The book has ['author', 'category', 'id', 'name', 'pages', 'price'], and the headphones have ['category', 'colors', 'id', 'name', 'price', 'specs']. The nested field is queryable right away: the wireless query returns [{'id': 'hp-201', 'hours': 30}].

So what do we give up compared with a relational database? Joins across tables and cheap ad hoc queries. In return we get predictable speed at any scale.

Design for the queries, not for tables

I design containers around the app's main queries, never around normalized tables.

Question 2: A new teammate asks how accounts, databases, containers and items fit together. How do you explain it?

It's a hierarchy. Let's walk down it:

  • Account - endpoint, regions, keys
  • Database - a group of containers, like shop
  • Containers - partition key, throughput
  • Items - JSON documents

The container is where we choose the partition key, and an item is one JSON document.

Let's see it on the emulator. hierarchy.py adds the carts and orders containers to the shop database, both partitioned by /customerId, and writes one cart. Then it prints the tree from the top. We run python hierarchy.py.

hierarchy.py
import os
from azure.cosmos import PartitionKey
from common import shop

carts = shop.create_container_if_not_exists(
    "carts", partition_key=PartitionKey(path="/customerId"))
orders = shop.create_container_if_not_exists(
    "orders", partition_key=PartitionKey(path="/customerId"))
carts.upsert_item({"id": "cart-c1", "customerId": "c1",
                   "lines": [{"sku": "bk-101", "qty": 1}]})

print("account:  ", os.environ["COSMOS_ENDPOINT"])
print("database: ", shop.id)
for c in [shop.get_container_client("products"), carts, orders]:
    print("container:", c.id, "| partition key",
          c.read()["partitionKey"]["paths"])
item = carts.read_item("cart-c1", partition_key="c1")
print("item:     ", item["id"], "| logical partition",
      item["customerId"])
Terminal
$ python hierarchy.py
account:   http://localhost:8081
database:  shop
container: products | partition key ['/category']
container: carts | partition key ['/customerId']
container: orders | partition key ['/customerId']
item:      cart-c1 | logical partition c1

The output walks down the tree: the account is http://localhost:8081, the database is shop, then three containers with their partition keys: products on ['/category'], carts and orders on ['/customerId']. Last, cart-c1 sits in logical partition c1.

The container is the unit of scale. It has its own throughput, or shares the database's, and its data is split by the partition key chosen at creation.

Other APIs use other words for the same levels:

LevelNoSQLMongoDBCassandra
Databasedatabasedatabasekeyspace
Containercontainercollectiontable
Itemitemdocumentrow
The limit to remember

500 databases and containers per account, and it can't be raised. So never a container per customer: customers belong in the partition key.

Question 3: Someone asks which API to pick: NoSQL, MongoDB, Cassandra, Gremlin, Table or PostgreSQL. How do you choose?

Pick by the code and the drivers you already have. For a brand new application, my default is the API for NoSQL. It's the native one, with a SQL-like query language over JSON, and automatic indexing.

Let's go through the six:

APIWhat Microsoft says it is forChoose it when
NoSQLnative SQL queries, automatic indexing, schema flexibilitya new app: my default
MongoDBfull wire protocol compatibility, familiar MongoDB toolsexisting MongoDB code
CassandraCassandra Query Language (CQL)existing Cassandra code
Gremlingraph traversal languagegraph questions
Tablemodernize Azure Table Storage applicationsexisting Table Storage code
PostgreSQLdistributed relational apps, PostgreSQL wire protocolretirement path: not for new apps

The MongoDB API offers full wire protocol compatibility, so existing MongoDB apps and tools keep working. Cassandra speaks CQL. Gremlin is for graph traversals. Table modernizes Azure Table Storage apps.

PostgreSQL is the odd one out: distributed relational, over the PostgreSQL wire protocol. But Microsoft now puts it on a retirement path, so it's not for new projects.

Watch the naming in interviews too. The vCore-based MongoDB offering is now its own product, Azure DocumentDB. It's separate from the Cosmos DB API for MongoDB, which runs on request units.

The emulator we use in this series runs only the API for NoSQL, so every script here uses it.

Real project

Features differ between APIs. Before I commit to one, I check that every feature I need exists on it.

Question 4: A teammate asks what the system properties like id, _etag and _ts on every item are for. How do you explain them?

The id is ours: a string, unique within one logical partition. The rest come from Cosmos DB.

PropertySet byWhat it is for
idyouunique name within a logical partition
_etagCosmos DBentity tag for optimistic concurrency: changes on every write
_tsCosmos DBtime stamp of the last update
_rid, _selfCosmos DBinternal unique id and addressable URI
_lsnCosmos DBpresent in change feed payloads only

Let's look at them on a real item. sysprops.py creates order o-1001 and prints only the property names. Then it updates the status to paid, and tries a replace that sends the old _etag. errors.py then tests the id rules. We run python sysprops.py and python errors.py.

sysprops.py
import time
from azure.core import MatchConditions
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
from common import shop

orders = shop.get_container_client("orders")
item = orders.create_item({"id": "o-1001", "customerId": "c1",
                           "status": "new", "total": 42.5})
print("properties:", sorted(k for k in item
                            if k.startswith("_") or k == "id"))
print("_ts is epoch seconds:", abs(time.time() - item["_ts"]) < 60)

old_etag = item["_etag"]
item["status"] = "paid"
updated = orders.replace_item("o-1001", item)
print("status:", updated["status"],
      "| _etag changed:", updated["_etag"] != old_etag)
try:
    orders.replace_item("o-1001", item, etag=old_etag,
                        match_condition=MatchConditions.IfNotModified)
except CosmosAccessConditionFailedError as e:
    print("replace with the old _etag:", e.status_code)
errors.py
from azure.cosmos.exceptions import CosmosHttpResponseError
from common import shop

orders = shop.get_container_client("orders")
order = {"id": "o-1001", "customerId": "c1", "status": "new"}


def attempt(label, call):
    try:
        call()
        print(label, "-> OK")
    except CosmosHttpResponseError as e:
        print(label, "->", type(e).__name__, e.status_code)


attempt("create o-1001 in c1", lambda: orders.create_item(order))
attempt("create o-1001 in c2", lambda: orders.create_item(
    dict(order, customerId="c2")))
attempt("read o-9999 in c1", lambda: orders.read_item(
    "o-9999", partition_key="c1"))
attempt("read o-1001 in c3", lambda: orders.read_item(
    "o-1001", partition_key="c3"))
Terminal
$ python sysprops.py
properties: ['_attachments', '_etag', '_rid', '_self', '_ts', 'id']
_ts is epoch seconds: True
status: paid | _etag changed: True
replace with the old _etag: 412
$ python errors.py
create o-1001 in c1 -> CosmosResourceExistsError 409
create o-1001 in c2 -> OK
read o-9999 in c1 -> CosmosResourceNotFoundError 404
read o-1001 in c3 -> CosmosResourceNotFoundError 404

First the names: ['_attachments', '_etag', '_rid', '_self', '_ts', 'id'], and _ts is epoch seconds: True. After the update to paid, _etag changed: True. A replace that sends the old _etag as its if-match condition is rejected with 412. That's optimistic concurrency.

Then the id rules. Creating o-1001 again in partition c1 is CosmosResourceExistsError 409, but under customer c2 it's OK. Reading a missing id, o-9999, is a 404, and so is reading o-1001 with the wrong partition key, c3.

So id plus partition key is the real primary key.

For the data lake

I drop the internal fields like _rid and _self, but keep _ts as the load watermark.

Question 5: Your manager asks when Cosmos DB is the wrong choice. What do you tell them?

When the workload is relational at heart. Let's go through the cases one by one:

  • Joins across items or containers - a JOIN works only inside one item
  • Transactions across partitions - ACID only within one logical partition
  • Large files - 2 MB per item: binaries go to Blob Storage
  • Heavy ad-hoc analytics - mirror to Microsoft Fabric instead

A transaction covers one logical partition, so a change across many customers can't be all or nothing.

Now let's try a big file. toobig.py stores a 2.2 MB scanned invoice as a field on an order. We run python toobig.py.

toobig.py
from azure.cosmos.exceptions import CosmosHttpResponseError
from common import shop

orders = shop.get_container_client("orders")
scan = "x" * 2_200_000                    # a 2.2 MB scanned invoice
try:
    orders.create_item({"id": "inv-7001", "customerId": "c1",
                        "pdf": scan})
except CosmosHttpResponseError as e:
    print(type(e).__name__, e.status_code)
    print(str(e).split("\n")[0])
Terminal
$ python toobig.py
CosmosHttpResponseError 413
(RequestEntityTooLarge) Entity with the specified id is larger than the maximum entity size (2 MiB).
  Entity size: 2200044 bytes.

The emulator rejects it: CosmosHttpResponseError 413, (RequestEntityTooLarge), larger than the maximum entity size of 2 MiB. Keep files like that in Blob Storage, and store only the link in the item. Microsoft calls large binaries in Cosmos DB an anti-pattern.

Heavy ad hoc analytics is the last case. Big scans burn the request units the app needs. So we mirror the operational container into Microsoft Fabric, near real-time and not on our request units, and report from OneLake with SQL, Spark or Power BI.

My honest answer

If the access patterns aren't known, and the team needs flexible reporting with joins, start relational. Cosmos DB shines when you know the queries and need scale and low latency.

Question 6: Someone asks the difference between provisioned throughput, autoscale and serverless. How do you decide?

All three buy request units. Provisioned, or manual, is a fixed number of request units per second. Autoscale scales up to a maximum we set. Serverless has no throughput setting at all.

Provisioned (manual)AutoscaleServerless
You setfixed RU/s, steps of 100a max: scales 10% to 100%nothing
Billed onRU/s provisioned, per hourhighest RU/s each hourRUs consumed + storage
Minimum400 RU/s per containermax 1,000 RU/s, steps of 1,000no minimum charge
Regionsany numberany numberone region
Per physical partition10,000 RU/s10,000 RU/s5,000 RU/s

Let's take them one at a time. Manual is set in steps of 100 and billed by the hour, whether we use it or not. Autoscale takes a maximum and scales between 10 percent of it and the full maximum, billing each hour at the highest throughput reached. Microsoft says it saves money if you need the maximum for 66 percent of the hours or fewer. Serverless bills the request units consumed, plus storage. But it's single region, and each physical partition handles up to 5,000 request units per second.

In Python, manual and autoscale are the offer_throughput argument. The emulator accepts throughput but doesn't enforce it, so this is code.

throughput.py (Azure, not run)
from azure.cosmos import PartitionKey, ThroughputProperties

# Provisioned (manual): a fixed 400 RU/s, billed per hour
shop.create_container("orders", PartitionKey(path="/customerId"),
                      offer_throughput=400)

# Autoscale: between 400 and 4,000 RU/s, billed on each hour's peak
shop.create_container("carts", PartitionKey(path="/customerId"),
    offer_throughput=ThroughputProperties(
        auto_scale_max_throughput=4000))

Serverless is chosen when we create the account:

serverless.sh (Azure, not run)
# Serverless: a capability chosen when the account is created
az cosmosdb create -n cosmos-shop-dev -g rg-shop \
  --capabilities EnableServerless

My rule of thumb:

  • Steady traffic - manual
  • Spiky traffic - autoscale
  • Dev, test and intermittent apps - serverless
Free tier

1,000 RU/s and 25 GB free, one account per subscription, and not on serverless.

Scenario 7: The business wants a product catalog and shopping cart that answer in milliseconds for customers worldwide. How would you design it?

Two containers: products, partitioned by /category, and carts, partitioned by /customerId, one cart per shopper. Every hot path is a point read by id and partition key, or a single-partition query.

  • Shoppers - worldwide
  • App in each region - nearest region first
  • products - key /category: point reads, category pages
  • carts - key /customerId: one document per shopper

Let's run the three hot paths. storefront.py adds a second book, reads the product page with a point read, runs the category page as a query inside the books partition, and adds a line to the cart with a patch. We run python storefront.py.

storefront.py
from common import shop

products = shop.get_container_client("products")    # key: /category
carts = shop.get_container_client("carts")          # key: /customerId
products.upsert_item({"id": "bk-102", "category": "books",
                      "name": "Spark Field Guide", "price": 24.5})

p = products.read_item("bk-101", partition_key="books")  # point read
print("product page:", p["name"], p["price"])

q = "SELECT c.id, c.price FROM c ORDER BY c.price"   # one partition
for r in products.query_items(q, partition_key="books"):
    print("  books:", r["id"], r["price"])

new_line = {"sku": "bk-102", "qty": 2}
ops = [{"op": "add", "path": "/lines/-", "value": new_line}]   # append
cart = carts.patch_item("cart-c1", partition_key="c1",
                        patch_operations=ops)
print("cart:", cart["id"],
      [(x["sku"], x["qty"]) for x in cart["lines"]])
Terminal
$ python storefront.py
product page: Python for Data Teams 39.5
  books: bk-102 24.5
  books: bk-101 39.5
cart: cart-c1 [('bk-101', 1), ('bk-102', 2)]

The product page is Python for Data Teams 39.5. A point read is the cheapest operation: on Azure, about 1 request unit for a 1 KB item. The category page lists bk-102 24.5 and bk-101 39.5, sorted by price, without leaving the partition. The patch appends one line, so the app never resends the whole cart: cart-c1 [('bk-101', 1), ('bk-102', 2)].

For customers worldwide, we replicate to the regions where they shop. Multi-region writes let carts be written locally. The emulator has one region, so this is code.

account.sh (Azure, not run)
# Regions near the shoppers (not run: the emulator has one region)
az cosmosdb create -n cosmos-shop -g rg-shop \
  --locations regionName=eastus failoverPriority=0 \
  --locations regionName=westeurope failoverPriority=1 \
  --locations regionName=southeastasia failoverPriority=2 \
  --enable-multiple-write-locations true \
  --default-consistency-level Session

Each app lists its nearest region first:

app_client.py (Azure, not run)
# The app in Europe reads and writes in the nearest region
client = CosmosClient(URL, credential=DefaultAzureCredential(),
                      multiple_write_locations=True,
                      preferred_locations=["West Europe", "East US"])

Keep the default Session consistency, and use autoscale for sale days.

The trap

One category growing huge or hot. Then key the catalog by product id, and serve category pages from a cache or a search index.

Key points to remember

  • A fully managed NoSQL database: schema-agnostic JSON, automatic indexing, scale-out, global
  • Account → database → container (partition key, throughput) → item
  • API for NoSQL for new apps; the others for existing code; Azure DocumentDB is separate
  • id + partition key identify an item; _etag for concurrency, _ts last write
  • Manual for steady, autoscale for spiky, serverless for intermittent traffic

The full script

This is a Python script that writes every file and runs every command above in order against the Cosmos DB emulator: run pip install azure-cosmos first, and set COSMOS_ENDPOINT and COSMOS_KEY.

Show the full script that writes the files and runs every step
Full script - writes the files and runs every step against the Cosmos DB emulator (pip install azure-cosmos), run it with Python
# ========================================================================
# Cosmos DB Interview Q&A #1 - Cosmos DB fundamentals and architecture
# TechBrothersIT. Names and sample data are invented for teaching.
# Every step below was run on the official Azure Cosmos DB Linux emulator (vNext, Docker image)
# with azure-cosmos 4.17.1; the outputs in the video and the blog post are the real outputs.
# To run it yourself:
#   1. docker run -p 8081:8081 -p 1234:1234 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
#      and wait until its log says "Now listening on: http://0.0.0.0:8081".
#   2. pip install azure-cosmos
#   3. Set COSMOS_ENDPOINT=http://localhost:8081 and COSMOS_KEY to the emulator key
#      (C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==),
#      then run python CosmosDB_Interview_QA_01_Code.py. The scripts create their own databases and containers.
# Run it in an empty folder and on a freshly started emulator: it creates its files (and any local data
# files) there, and a second run on old data gives different output.
# Steps that restart the emulator say so in a comment: stop and start it by hand at that point.
# ========================================================================

import os, subprocess, time

def write(path, text):
    if text is None:
        if os.path.exists(path): os.remove(path)
        return
    os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
    with open(path, "w", encoding="utf-8") as f:
        f.write(text.strip("\n") + "\n")

def run(cmd, expect_error=False, allow_error=False, env=None):
    print("\n$ " + cmd, flush=True)
    rc = subprocess.run(cmd, shell=True, env=dict(os.environ, **(env or {}))).returncode
    if rc != 0 and not (expect_error or allow_error):
        raise SystemExit("stopped: this command was expected to succeed")

# Step 0: the starting files
write('common.py', 'import os\nfrom azure.cosmos import CosmosClient\n\nclient = CosmosClient(os.environ["COSMOS_ENDPOINT"],\n                      credential=os.environ["COSMOS_KEY"])\nshop = client.create_database_if_not_exists("shop")\n\n\ndef mine(item):\n    """Your own fields only: drop _rid, _etag, _ts and friends."""\n    return {k: item[k] for k in sorted(item) if not k.startswith("_")}\n')

# Step 1: Schema-agnostic: a book and headphones with different shapes in one products container
write('flexible.py', """\
from azure.cosmos import PartitionKey
from common import shop, mine

products = shop.create_container_if_not_exists(
    "products", partition_key=PartitionKey(path="/category"))
products.upsert_item({"id": "bk-101", "category": "books",
                      "name": "Python for Data Teams", "price": 39.5,
                      "author": "S. Malik", "pages": 320})
products.upsert_item({"id": "hp-201", "category": "audio",
                      "name": "Studio Headphones", "price": 89.9,
                      "colors": ["black", "white"],
                      "specs": {"wireless": True, "hours": 30}})
for p in products.query_items("SELECT * FROM c ORDER BY c.id",
                              enable_cross_partition_query=True):
    print(p["id"], list(mine(p)))
q = "SELECT c.id, c.specs.hours FROM c WHERE c.specs.wireless = true"
print("wireless:", list(products.query_items(
    q, enable_cross_partition_query=True)))
""")
run('python flexible.py')

# Step 2: The resource hierarchy: account, database, containers with partition keys, an item
write('hierarchy.py', """\
import os
from azure.cosmos import PartitionKey
from common import shop

carts = shop.create_container_if_not_exists(
    "carts", partition_key=PartitionKey(path="/customerId"))
orders = shop.create_container_if_not_exists(
    "orders", partition_key=PartitionKey(path="/customerId"))
carts.upsert_item({"id": "cart-c1", "customerId": "c1",
                   "lines": [{"sku": "bk-101", "qty": 1}]})

print("account:  ", os.environ["COSMOS_ENDPOINT"])
print("database: ", shop.id)
for c in [shop.get_container_client("products"), carts, orders]:
    print("container:", c.id, "| partition key",
          c.read()["partitionKey"]["paths"])
item = carts.read_item("cart-c1", partition_key="c1")
print("item:     ", item["id"], "| logical partition",
      item["customerId"])
""")
run('python hierarchy.py')

# Step 3: System properties, an etag that changes on update (412 when stale), and the id rules (409 and 404)
write('sysprops.py', """\
import time
from azure.core import MatchConditions
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
from common import shop

orders = shop.get_container_client("orders")
item = orders.create_item({"id": "o-1001", "customerId": "c1",
                           "status": "new", "total": 42.5})
print("properties:", sorted(k for k in item
                            if k.startswith("_") or k == "id"))
print("_ts is epoch seconds:", abs(time.time() - item["_ts"]) < 60)

old_etag = item["_etag"]
item["status"] = "paid"
updated = orders.replace_item("o-1001", item)
print("status:", updated["status"],
      "| _etag changed:", updated["_etag"] != old_etag)
try:
    orders.replace_item("o-1001", item, etag=old_etag,
                        match_condition=MatchConditions.IfNotModified)
except CosmosAccessConditionFailedError as e:
    print("replace with the old _etag:", e.status_code)
""")
write('errors.py', """\
from azure.cosmos.exceptions import CosmosHttpResponseError
from common import shop

orders = shop.get_container_client("orders")
order = {"id": "o-1001", "customerId": "c1", "status": "new"}


def attempt(label, call):
    try:
        call()
        print(label, "-> OK")
    except CosmosHttpResponseError as e:
        print(label, "->", type(e).__name__, e.status_code)


attempt("create o-1001 in c1", lambda: orders.create_item(order))
attempt("create o-1001 in c2", lambda: orders.create_item(
    dict(order, customerId="c2")))
attempt("read o-9999 in c1", lambda: orders.read_item(
    "o-9999", partition_key="c1"))
attempt("read o-1001 in c3", lambda: orders.read_item(
    "o-1001", partition_key="c3"))
""")
run('python sysprops.py')
run('python errors.py')

# Step 4: A 2.2 MB item is rejected: the 2 MB item limit
write('toobig.py', 'from azure.cosmos.exceptions import CosmosHttpResponseError\nfrom common import shop\n\norders = shop.get_container_client("orders")\nscan = "x" * 2_200_000                    # a 2.2 MB scanned invoice\ntry:\n    orders.create_item({"id": "inv-7001", "customerId": "c1",\n                        "pdf": scan})\nexcept CosmosHttpResponseError as e:\n    print(type(e).__name__, e.status_code)\n    print(str(e).split("\\n")[0])\n')
run('python toobig.py')

# Step 5: Storefront: product point read, a single-partition category query, a cart patch
write('storefront.py', """\
from common import shop

products = shop.get_container_client("products")    # key: /category
carts = shop.get_container_client("carts")          # key: /customerId
products.upsert_item({"id": "bk-102", "category": "books",
                      "name": "Spark Field Guide", "price": 24.5})

p = products.read_item("bk-101", partition_key="books")  # point read
print("product page:", p["name"], p["price"])

q = "SELECT c.id, c.price FROM c ORDER BY c.price"   # one partition
for r in products.query_items(q, partition_key="books"):
    print("  books:", r["id"], r["price"])

new_line = {"sku": "bk-102", "qty": 2}
ops = [{"op": "add", "path": "/lines/-", "value": new_line}]   # append
cart = carts.patch_item("cart-c1", partition_key="c1",
                        patch_operations=ops)
print("cart:", cart["id"],
      [(x["sku"], x["qty"]) for x in cart["lines"]])
""")
run('python storefront.py')
Next in this series

Part 2: Partitioning and Partition Keys

The sample data on this page is invented for teaching. Every terminal output is the real output of the command above it, run on the official Azure Cosmos DB Linux emulator (vNext) with azure-cosmos 4.17.1. Features the emulator does not support are shown as code. Part of the Real Time Azure Cosmos DB Interview Questions and Answers series on TechBrothersIT. Features, limits and their status (GA or preview) are current as of October 2026; check the official Azure Cosmos DB documentation (learn.microsoft.com/azure/cosmos-db) for anything you quote in an interview.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.