Mastering Stored Procedures, Triggers, and User-Defined Functions
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 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.
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 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.
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);
}
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.
UDF.FunctionName() syntax.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;
}
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
To effectively utilize server-side logic in Azure Cosmos DB, follow these best practices: