SQL API Resources
Patterns for managing SQL (Core) API databases, containers, and programmability objects.
SQL Database Operations
Create Database
using Azure.ResourceManager.CosmosDB;
using Azure.ResourceManager.CosmosDB.Models;
var databaseData = new CosmosDBSqlDatabaseCreateOrUpdateContent(
new CosmosDBSqlDatabaseResourceInfo("my-database"));
var databaseCollection = account.GetCosmosDBSqlDatabases();
var operation = await databaseCollection.CreateOrUpdateAsync(
WaitUntil.Completed,
"my-database",
databaseData);
CosmosDBSqlDatabaseResource database = operation.Value;
Create Database with Shared Throughput
var databaseData = new CosmosDBSqlDatabaseCreateOrUpdateContent(
new CosmosDBSqlDatabaseResourceInfo("my-database"))
{
Options = new CosmosDBCreateUpdateConfig
{
Throughput = 400 // Shared across containers
}
};
// Or with autoscale
var databaseData = new CosmosDBSqlDatabaseCreateOrUpdateContent(
new CosmosDBSqlDatabaseResourceInfo("my-database"))
{
Options = new CosmosDBCreateUpdateConfig
{
AutoscaleSettings = new AutoscaleSettings
{
MaxThroughput = 4000
}
}
};
List Databases
await foreach (var db in account.GetCosmosDBSqlDatabases())
{
Console.WriteLine($"Database: {db.Data.Name}");
Console.WriteLine($" Resource ID: {db.Data.Resource.DatabaseName}");
}
Delete Database
var database = await account.GetCosmosDBSqlDatabaseAsync("my-database");
await database.Value.DeleteAsync(WaitUntil.Completed);
SQL Container Operations
Create Container with Partition Key
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/tenantId" },
Kind = CosmosDBPartitionKind.Hash,
Version = 2 // Use V2 for hierarchical partition keys
}
});
var containerCollection = database.GetCosmosDBSqlContainers();
var operation = await containerCollection.CreateOrUpdateAsync(
WaitUntil.Completed,
"my-container",
containerData);
Hierarchical Partition Key (V2)
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/tenantId", "/userId", "/sessionId" },
Kind = CosmosDBPartitionKind.MultiHash,
Version = 2
}
});
Create Container with Indexing Policy
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/partitionKey" },
Kind = CosmosDBPartitionKind.Hash
},
IndexingPolicy = new CosmosDBIndexingPolicy
{
Automatic = true,
IndexingMode = CosmosDBIndexingMode.Consistent,
// Include paths
IncludedPaths =
{
new CosmosDBIncludedPath { Path = "/*" }
},
// Exclude paths
ExcludedPaths =
{
new CosmosDBExcludedPath { Path = "/largeTextField/*" },
new CosmosDBExcludedPath { Path = "/_etag/?" }
},
// Composite indexes for ORDER BY on multiple fields
CompositeIndexes =
{
new CosmosDBCompositePath[]
{
new() { Path = "/name", Order = CompositePathSortOrder.Ascending },
new() { Path = "/timestamp", Order = CompositePathSortOrder.Descending }
}
},
// Spatial indexes
SpatialIndexes =
{
new SpatialSpec
{
Path = "/location/*",
Types = { SpatialType.Point, SpatialType.Polygon }
}
}
}
});
Create Container with TTL
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/partitionKey" },
Kind = CosmosDBPartitionKind.Hash
},
// Default TTL in seconds (-1 = off, 0 = on but no default, >0 = default seconds)
DefaultTtl = 86400 // 24 hours
});
Create Container with Unique Keys
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/tenantId" },
Kind = CosmosDBPartitionKind.Hash
},
UniqueKeys = new CosmosDBUniqueKeyPolicy
{
UniqueKeys =
{
new CosmosDBUniqueKey
{
Paths = { "/email" }
},
new CosmosDBUniqueKey
{
Paths = { "/department", "/employeeId" }
}
}
}
});
Create Container with Dedicated Throughput
var containerData = new CosmosDBSqlContainerCreateOrUpdateContent(
new CosmosDBSqlContainerResourceInfo("my-container")
{
PartitionKey = new CosmosDBContainerPartitionKey
{
Paths = { "/partitionKey" },
Kind = CosmosDBPartitionKind.Hash
}
})
{
Options = new CosmosDBCreateUpdateConfig
{
Throughput = 1000 // Dedicated to this container
}
};
List Containers
await foreach (var container in database.GetCosmosDBSqlContainers())
{
Console.WriteLine($"Container: {container.Data.Name}");
Console.WriteLine($" Partition Key: {string.Join(", ", container.Data.Resource.PartitionKey.Paths)}");
Console.WriteLine($" Default TTL: {container.Data.Resource.DefaultTtl}");
}
Delete Container
var container = await database.GetCosmosDBSqlContainerAsync("my-container");
await container.Value.DeleteAsync(WaitUntil.Completed);
Stored Procedures
Create Stored Procedure
var sprocData = new CosmosDBSqlStoredProcedureCreateOrUpdateContent(
new CosmosDBSqlStoredProcedureResourceInfo("bulkDelete")
{
Body = @"
function bulkDelete(query) {
var context = getContext();
var container = context.getCollection();
var response = context.getResponse();
var deleted = 0;
var accepted = container.queryDocuments(
container.getSelfLink(),
query,
function(err, docs) {
if (err) throw err;
docs.forEach(function(doc) {
container.deleteDocument(doc._self);
deleted++;
});
response.setBody({ deleted: deleted });
}
);
if (!accepted) {
response.setBody({ deleted: deleted, continuation: true });
}
}"
});
var sprocCollection = container.GetCosmosDBSqlStoredProcedures();
await sprocCollection.CreateOrUpdateAsync(
WaitUntil.Completed,
"bulkDelete",
sprocData);
List Stored Procedures
await foreach (var sproc in container.GetCosmosDBSqlStoredProcedures())
{
Console.WriteLine($"Stored Procedure: {sproc.Data.Name}");
}
Triggers
Create Trigger
var triggerData = new CosmosDBSqlTriggerCreateOrUpdateContent(
new CosmosDBSqlTriggerResourceInfo("validateDocument")
{
Body = @"
function validateDocument() {
var context = getContext();
var request = context.getRequest();
var doc = request.getBody();
if (!doc.createdAt) {
doc.createdAt = new Date().toISOString();
}
request.setBody(doc);
}",
TriggerType = CosmosDBSqlTriggerType.Pre,
TriggerOperation = CosmosDBSqlTriggerOperation.Create
});
var triggerCollection = container.GetCosmosDBSqlTriggers();
await triggerCollection.CreateOrUpdateAsync(
WaitUntil.Completed,
"validateDocument",
triggerData);
Trigger Types
| Type |
When |
Pre |
Before the operation |
Post |
After the operation |
Trigger Operations
| Operation |
Applies To |
All |
All operations |
Create |
Document creation |
Update |
Document updates |
Delete |
Document deletion |
Replace |
Document replacement |
User Defined Functions (UDFs)
Create UDF
var udfData = new CosmosDBSqlUserDefinedFunctionCreateOrUpdateContent(
new CosmosDBSqlUserDefinedFunctionResourceInfo("formatCurrency")
{
Body = @"
function formatCurrency(amount, currency) {
return currency + ' ' + amount.toFixed(2);
}"
});
var udfCollection = container.GetCosmosDBSqlUserDefinedFunctions();
await udfCollection.CreateOrUpdateAsync(
WaitUntil.Completed,
"formatCurrency",
udfData);
Partition Key Strategies
| Strategy |
Path Example |
Use Case |
| Single property |
/tenantId |
Multi-tenant apps |
| Synthetic key |
/partitionKey |
Computed from multiple fields |
| Hierarchical |
/tenantId, /userId |
Large tenants with sub-partitioning |
| ID-based |
/id |
Even distribution, no cross-partition queries |
Choosing Partition Key
- High cardinality — Many distinct values
- Even distribution — No hot partitions
- Query alignment — Most queries include partition key
- Immutable — Cannot change after document creation