Azure Cosmos DB: The Ultimate Developer’s Cheat Sheet

Introduction: What is Azure Cosmos DB and Why It Matters

Azure Cosmos DB is Microsoft’s globally distributed, multi-model database service designed for mission-critical applications. It provides turnkey global distribution, elastic scaling of throughput and storage, sub-10ms latencies, and guaranteed high availability, all backed by industry-leading SLAs.

Why It Matters:

  • Global Distribution: Deploy databases to any Azure region with the click of a button
  • Multi-Model Support: Supports document, key-value, graph, and column-family data models
  • Elastic Scalability: Scale throughput and storage on-demand without downtime
  • Comprehensive SLAs: Guarantees for availability, latency, throughput, and consistency

Core Concepts and Principles

Data Models

Model TypeAPIBest For
DocumentSQL API (Core)General purpose document storage, CRUD operations, querying
Key-ValueTable APISimple key-value data storage
GraphGremlin APIRelationships and graph traversals
Column-FamilyCassandra APIWide-column storage, high write throughput
MongoDBMongoDB APIMongoDB compatibility

Cosmos DB Structure

  • Account: Container for databases, region configuration, account-level settings
  • Database: Container for containers, database-level settings
  • Container (Collection/Table/Graph): Schema-agnostic container for items, partition key, indexing policy
  • Item (Document/Row/Node/Edge): The data stored within a container

Consistency Levels

LevelDescriptionGuaranteeUse Case
StrongLinearizabilityReads return most recent committed versionFinancial transactions
Bounded StalenessConsistent prefix; reads lag by k versions or t timeReads return consistent version within boundsStatus updates, product reviews
SessionConsistent prefix; reads consistent within single client sessionMonotonic reads, writes, read-your-writesSocial media, shopping cart
Consistent PrefixUpdates returned in order, no gapsReads never see out-of-order writesStatus updates, tracking
EventualNo ordering guaranteeEventual convergence of replicasNon-ordered data (counts, likes)

Request Units (RUs)

Request Units (RUs) are the currency of throughput in Cosmos DB.

  • 1 RU = Resources to read a 1KB item
  • Operations cost varies:
    • Point reads: ~1 RU (1KB document)
    • Writes: ~5-10 RUs (1KB document)
    • Queries: Variable (depends on complexity, items returned)

Provisioning Options:

  • Provisioned Throughput: Fixed RU/s allocation
  • Autoscale: Automatically scales between max and min (10%) RU/s
  • Serverless: Pay only for consumed resources, no minimum

Partitioning

Partition Key Selection

Good partition keys:

  • Have high cardinality (many unique values)
  • Distribute requests evenly (avoid hot partitions)
  • Distribute data evenly (balance storage)
Common Partition KeysEvaluation
User IDGood for user-centric applications
Tenant IDGood for multi-tenant applications
Device IDGood for IoT scenarios
Timestamp/DateMay cause hot partitions unless distributed
Department/CategoryMay cause uneven distribution

Synthetic Partition Keys

For better distribution, consider composite keys:

// Example: Combining tenant ID and entity type
partitionKey = `${tenantId}-${entityType}`

Step-by-Step Processes

Creating a Cosmos DB Account and Database

  1. Create Account:

    • Navigate to Azure Portal
    • Create resource → Azure Cosmos DB
    • Select API type (SQL, MongoDB, etc.)
    • Choose subscription, resource group, account name
    • Configure capacity mode (provisioned/serverless)
    • Set replication regions
    • Configure availability zones and VNET settings
  2. Create Database:

    • In Cosmos DB account, select “Data Explorer”
    • “New Database”
    • Name database and set throughput (shared or dedicated)
  3. Create Container:

    • Select “New Container”
    • Set container ID
    • Define partition key
    • Configure RU/s (if dedicated)
    • Set indexing policy and TTL

Writing Data to Cosmos DB

  1. Connect to Database:

    CosmosClient client = new CosmosClient(EndpointUri, PrimaryKey);
    Database database = client.GetDatabase("DatabaseId");
    Container container = database.GetContainer("ContainerId");
    
  2. Create Document:

    // Create item
    dynamic newItem = new
    {
        id = "1",
        pk = "partitionKey1",
        name = "Item Name",
        description = "Item Description"
    };
    
    // Add to container
    ItemResponse<dynamic> response = await container.CreateItemAsync(newItem, new PartitionKey("partitionKey1"));
    
  3. Read Document:

    // Point read (most efficient)
    ItemResponse<dynamic> response = await container.ReadItemAsync<dynamic>("1", new PartitionKey("partitionKey1"));
    
    // Query
    QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.name = @name")
        .WithParameter("@name", "Item Name");
    FeedIterator<dynamic> resultSet = container.GetItemQueryIterator<dynamic>(query);
    

Key Techniques and Methods

Optimizing Costs

  1. Partition Key Optimization:

    • Choose keys that distribute traffic evenly
    • Avoid cross-partition queries
    • Batch operations when possible
  2. Indexing Policy Optimization:

    • Exclude unused paths
    • Use composite indexes for multi-property queries
    • Use spatial indexes only when needed
  3. RU Optimization:

    • Monitor RU consumption
    • Use autoscale for variable workloads
    • Consider time-of-day scaling

Sample Indexing Policy

{
  "indexingMode": "consistent",
  "automatic": true,
  "includedPaths": [
    {
      "path": "/*"
    }
  ],
  "excludedPaths": [
    {
      "path": "/path/to/rarely/queried/property/*"
    }
  ],
  "compositeIndexes": [
    [
      {
        "path": "/orderDate",
        "order": "ascending"
      },
      {
        "path": "/customerId",
        "order": "ascending"
      }
    ]
  ]
}

Querying Techniques

  1. Efficient Queries:

    • Always include partition key in filters
    • Use parameters to avoid SQL injection
    • Limit returned properties with projections
    • Use TOP/OFFSET for pagination
  2. Common Query Patterns:

    -- Point read (most efficient)
    SELECT * FROM c WHERE c.id = "item1" AND c.pk = "partition1"
    
    -- Range query
    SELECT * FROM c WHERE c.pk = "partition1" AND c.timestamp BETWEEN "2023-01-01" AND "2023-01-31"
    
    -- Aggregation
    SELECT COUNT(1) AS count FROM c WHERE c.pk = "partition1" AND c.category = "electronics"
    

Common Challenges and Solutions

ChallengeSolution
High RU consumptionOptimize queries, refine indexing policy, batch operations
Hot partitionsRevise partition key strategy, implement synthetic keys
Query timeoutsOptimize queries, increase RUs, check for cross-partition operations
Large document sizesSplit documents, use references between documents
High latencyDeploy to closer regions, optimize consistency level
Data consistency issuesUse appropriate consistency level for your scenario
Scaling costsImplement TTL, archive old data, use autoscale

Best Practices

Data Modeling

  • Denormalize data for common access patterns
  • Embed related data within a single document when possible
  • Keep documents under 2MB (hard limit)
  • Use references for many-to-many relationships or very large related data
  • Design for query patterns, not entity relationships

Performance Optimization

  • Store related data in the same partition
  • Use point reads whenever possible (id + partition key)
  • Batch operations to reduce network overhead
  • Use TTL to automatically expire data
  • Monitor and adjust RUs based on usage patterns
  • Use change feed for processing updates and maintaining derived data

Security Best Practices

  • Use Azure AD for authentication when possible
  • Implement least privilege access with role-based access control
  • Enable private endpoints for secure connectivity
  • Use customer-managed keys for sensitive data
  • Enable diagnostic logs for auditing
  • Use IP firewall rules to restrict access

SDK and API Quick Reference

REST API Examples

// Read document
GET https://{account}.documents.azure.com/dbs/{db-id}/colls/{coll-id}/docs/{doc-id}
Authorization: type%3dmaster%26ver%3d1.0%26sig%3d{signature}
x-ms-version: 2018-12-31
x-ms-date: {date}

SDK Examples (C#)

// Update document
ItemResponse<dynamic> response = await container.ReplaceItemAsync<dynamic>(
    item,
    id,
    new PartitionKey(partitionKey)
);

// Query with continuation token
QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.type = @type")
    .WithParameter("@type", "product");

FeedIterator<dynamic> resultSet = container.GetItemQueryIterator<dynamic>(
    query,
    requestOptions: new QueryRequestOptions { MaxItemCount = 100 }
);

while (resultSet.HasMoreResults)
{
    FeedResponse<dynamic> response = await resultSet.ReadNextAsync();
    foreach (var item in response)
    {
        Console.WriteLine(item.ToString());
    }
    // Use response.ContinuationToken for pagination
}

SDK Examples (JavaScript/Node.js)

// Create item
const { resource: createdItem } = await container.items.create(newItem);

// Query items
const querySpec = {
    query: "SELECT * FROM c WHERE c.category = @category",
    parameters: [
        {
            name: "@category",
            value: "electronics"
        }
    ]
};

const { resources: items } = await container.items.query(querySpec).fetchAll();

Resources for Further Learning

Official Documentation

Tools

Training and Learning

Community Resources

Scroll to Top