Azure Cosmos DB

Mastering Stored Procedures, Triggers, and User-Defined Functions

Leveraging Server-Side Logic in Cosmos DB

Azure Cosmos DB offers powerful server-side programming capabilities, allowing you to encapsulate business logic directly within your database. This enhances performance, security, and data consistency by executing code as close to the data as possible. The primary mechanisms for this are Stored Procedures, Triggers, and User-Defined Functions (UDFs).

Stored Procedures

Stored procedures allow you to execute a batch of operations atomically within Cosmos DB. They are written in JavaScript and are ideal for complex transactions, data manipulation, and enforcing business rules that span multiple documents.

Key Characteristics:

Example: Creating a new order and updating inventory

function createOrderAndReduceInventory(items) {
    var context = getContext();
    var collection = getCollection();
    var response = getBody(); // Expected to be an order object

    response.createdDate = new Date();
    response.status = 'Pending';

    // Validate items and reduce inventory (simplified)
    for (var i = 0; i < items.length; i++) {
        // For real-world, you'd query inventory collection
        // and throw error if insufficient stock.
        // For this example, we'll just log a message.
        log('Reducing inventory for item: ' + items[i].productId);
    }

    // Insert the order document
    collection.createDocument(response, function (err, orderDocument) {
        if (err) throw new Error('Error creating order: ' + err.message);

        // Respond with the created order
        context.getResponse().setBody(orderDocument);
    });
}

Triggers

Triggers are specialized stored procedures that execute automatically in response to a data modification operation (Create, Update, Delete). They can be either Pre- (run before the operation) or Post- (run after the operation) triggers.

Types of Triggers:

Use Cases:

Example: A Pre-Trigger to set a creation timestamp

This trigger automatically adds a createdAt field before a new document is created.

function setCreationTimestamp() {
    var context = getContext();
    var request = context.getRequest();
    var document = request.getBody();

    document.createdAt = new Date();

    request.setBody(document);
}

User-Defined Functions (UDFs)

UDFs are JavaScript functions that can be invoked within your Cosmos DB queries. They are designed for computations, data transformations, and complex calculations that can be performed on a per-document or per-item basis during query execution.

Key Features:

Example: Calculating distance based on coordinates

function calculateDistance(point1, point2) {
    var R = 6371; // Radius of the earth in km
    var dLat = toRadians(point2.latitude - point1.latitude);
    var dLon = toRadians(point2.longitude - point1.longitude);
    var a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(toRadians(point1.latitude)) * Math.cos(toRadians(point2.latitude)) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = R * c; // Distance in km
    return d;
}

function toRadians(degrees) {
    return degrees * Math.PI / 180;
}

Using the UDF in a query:

SELECT
    c.id,
    UDF.calculateDistance(c.location, { "latitude": 34.0522, "longitude": -118.2437 }) AS distanceToLA
FROM
    c
WHERE
    c.type = 'Store'
HAVING
    UDF.calculateDistance(c.location, { "latitude": 34.0522, "longitude": -118.2437 }) < 100

Best Practices

To effectively utilize server-side logic in Azure Cosmos DB, follow these best practices: