Skip to content

UDF and Triggers

One UDF and two types of Triggers - UDF = javascript of function (with parameter) to execute. await container.Scripts.CreateUserDefinedFunctionAsync(properties); - Pre Triggers = no parameters and executed before HTTP Post. await container.Scripts.CreateTriggerAsync(properties); - Post-triggers = run after an operation has completed and can have input parameters even though they are not required. They perform actions on the HTTP response message right before it is sent to the client.

Pre triggers can be used to - Validate. NOTE: You cannot use UDF as validation. - Modify data before insert/update - This is ONLY called via REST API or SDK, it's not build in.

Post triggers - respond/actions after response - This is ONLY called via REST API or SDK, it's not build in.

UDF - They are designed to transform, format, or filter data returned by a query. They are completely ignored during the process of saving a document to the database.

Triggers

Trigger for Pre/Post are ONLY via REST API and SDK (even Data explorer does not have this). Triggers are not conventional Database triggers, it needs to be manually invoked via REST Header (include) or defined in SDK.

  1. Via Rest API

    POST https://{databaseaccount}.documents.azure.com/dbs/{db}/colls/{coll}/docs
    Content-Type: application/json
    x-ms-version: 2018-12-31
    x-ms-documentdb-pre-trigger-include: myPreTriggerName
    Authorization: {your-auth-token}
    
    {
        "id": "123",
        "status": "pending"
    }
    

  2. Via SDK.

Step 1

create the trigger in portal or code Trigger Methods

TriggerProperties properties = new()
{
    Id = "addLabel",
    Body = preTrigger,
    TriggerOperation = TriggerOperation.Create,
    TriggerType = TriggerType.Pre
};

Step 2

Register/Invoke it via SDK When your application code performs a CreateItem or ReplaceItem operation using the SDK, you must pass the trigger's name within the RequestOptions (e.g., PreTriggerInclude).

ItemRequestOptions options = new()
{
    PreTriggers = new List<string> { "addLabel" },
    PostTriggers = new List<string> { "createView" }
};
await container.CreateItemAsync(newItem, requestOptions: options);

Trigger What are the "Create, Update, and Delete" operations for?

When you create a Trigger, you must register it for a specific operation. This is because a trigger doesn't "do" the work itself; it intercepts a request sent from your SDK.

Create: The trigger only runs when you call CreateItem. It is commonly used to add a createdAt timestamp or validate that required fields exist.

Update (Replace): The trigger only runs when you call ReplaceItem or UpsertItem. Useful for updating a modifiedAt field.

Delete: The trigger runs when an item is deleted. Often used as a "Post-Trigger" to log which user deleted the record into a separate audit container.

All: The trigger will run regardless of the operation type.

Scripts to trigger UDF

Script to call UDF must include udf

SELECT 
    p.name,
    p.price,
    udf.addTax(p.price) AS priceWithTax
FROM
    products p

Example of exists field check.

function detectField(doc, fieldName) {
    return doc[fieldName] !== undefined;
};

SELECT *
FROM c
WHERE udf.detectField(c, "reviews")

Versioning

It's good to store DB Version on schema changes. E.g. an item of {"staff_id", "name"} is changed to {"staff_id", "name", "address"}, by adding version e.g. {"version_id":2, "staff_id", "name", "address"}. Then you know that some records have address and while some doesn't. This is due to schema less cosmosdb design.

But to identify you can use User Defined Features to spot it. E.g. SELECT udf.address(p.address) FROM p, with address returning empty or the real value if found.