Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.
  • Labs icon Lab
  • A Cloud Guru
Azure icon
Labs

Implement Triggers on a Container in Cosmos DB for NoSQL

Operations over data stored in Cosmo DB for NoSQL are implemented through requests to the database and responses back from the database. Sometimes, we want to inject business logic during the request or after the operation has been completed. We can implement the business logic through a pre-trigger, which intercepts and acts on the request object or on a post-trigger, which intercepts the response object and takes additional actions from there. In this hands-on lab, you will get practice creating one of each type of trigger on a pre-deployed Cosmos DB database and then execute your triggers when an item is created. Students with experience using the Azure portal and Cosmos DB, and who are comfortable with any modern development language, will have the best opportunity to complete the lab without assistance; however, sample code, along with tips and hints, are provided in the lab objectives, and the full solution code for each objective is available in the lab guide.

Azure icon
Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 45m
Published
Clock icon Dec 16, 2022

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Housekeeping

    1. Open an incognito or in-private window and log in to the Azure portal using the username and password provided in the lab environment.
    2. From within the portal, initiate the Cloud Shell to select Bash (versus PowerShell) and set up with new backing storage.
    3. From the Bash command prompt, use the git clone command, followed by the URL provided in the Additional Information and Resources section of the lab, followed by DP420Labs to alias the downloaded folder to a friendly name.
    4. Once the project is downloaded, use Cloud Editor to open the Program.cs file.
    5. From the Bash command prompt, change to the working directory cd DP420Labs/DP420/Triggers.
  2. Challenge

    Create a Pre-Trigger to Add a Missing Property

    In this objective, you will code a pre-trigger that intercepts the create request with a special interest in the totalOperations property. The trigger code creates the property if it is missing and, in any case, sets the value to 0 (zero), regardless of any value it might already have assigned. Triggers are commonly created and called in Azure Cosmos DB SDK code, but in this objective, we want to leverage the user interface that is provided to help you understand the options available when defining triggers.

    Note: If you get stuck along the way, scroll down to the Hints and Tips section at the end of this objective before turning to the lab guide or the solution video.

    Update Program.cs File with the Cosmos DB Account Connection String

    After completing the last of the housekeeping tasks, you should have Cloud Shell open with the Program.cs file open in the editor. Take this opportunity to complete one last housekeeping task. (If you do it now, switching back and forth between Cloud Shell and a query window will be easier.)

    1. Once on the Azure Cosmos DB account overview page, copy the primary connection string (Note: Copy the full string).
    2. In the Cloud Shell Editor, replace the "[ConnectionString]" placeholder with the primary connection string you just copied. Be sure the connection string is wrapped in double quotes, and save the Program.cs file. The SDK code is now ready to test your triggers when the time comes.
    Set Up the Trigger
    1. Locate and select the database container called LabContainer.
    2. Use the menu in Data Explorer to create a new trigger.
    3. Create a pre-trigger to fire only when called using the Cosmos DB SDK for inserted items. Ensure you enter the exact Id for your trigger: addOpsCounter.

      Note: If you don't supply this exact value for the Id, the SDK code that tests this trigger will not work.

    4. In the trigger body, change the generic function name to be the same as the trigger Id: addOpsCounter.
    Code the Trigger
    1. Using the following code as your guide, create a trigger that captures the item that is about to be inserted into the container and handles the totalOperations property. If it is missing, add the property and set the value to 0 (zero). If the totalOperations property exists on the item, override any existing value with 0 (zero).
    2. Save (update) the trigger. This registers the trigger on the container.
    Sample Code

    Note: This code is only an example. It is not the exact code required to fulfill the objective, so do not copy/paste it and register it as your trigger; however, you can copy much of it into your trigger body and edit it to fulfill the requirements of the objective.

    function validatePeerCheck() {
        var context = getContext();
        var request = context.getRequest();
    
        // item to be created in the current operation
        var itemToCreate = request.getBody();
    
        // validate property
        //assign one value if it does not exists
        if (!("peerReviewed" in itemToCreate)) {
            itemToCreate["peerReviewed"] = "No";
        }
        //assign a different value if it exists
        else
        { 
            itemToCreate["peerReviewed"] = "Unknown";
        }
    
        // update the item that will be created
        request.setBody(itemToCreate);
    }
    

    Potential Quirks in the Portal User Interface

    • There may be a quirk in the portal UI where the Save/Update feature is disabled after you have edited the trigger. If this happens, just make a minor edit in the Id control, and then edit it back to the original value. This action should wake up the button for you to save your work.
    • In a separate issue, if the UI throws an error when you save or update the trigger, close the trigger blade (tab) and re-open the trigger listed in the Data Explorer under the container name. It should then show that you successfully saved the trigger.

    Tips and Hints

    • If you copy/paste the sample code, make sure you retain the function name you entered in one of the previous steps of this objective.
    • Don't forget to save your work after updating the trigger code.
    • Notice that the sample code assigns the two different values to the property, depending on whether or not it previously existed. Given the requirements in this objective, you might see an easier way to fulfill the objective with a little less code.
  3. Challenge

    Create a Post-Trigger to Update an Aggregation Property

    In this objective, you will code a post-trigger that intercepts the response object after any operation. The trigger will increment a property called totalOperations in order to keep track of the number of insert and update operations on the item. We do this in the post-trigger versus the pre-trigger for three reasons: 1) the pre-trigger is configured to run only on an insert operation, 2) the pre-trigger runs before the actual operation on the container has completed successfully, so it is premature to increment it, and 3) the post-trigger runs transactionally with the insert or update operation, so both will fail or succeed together, which ensures that the operation is successful before incrementing the totalOperations property.

    Triggers are commonly created and called in Azure Cosmos DB SDK code, but in this objective, we want to leverage the user interface that is provided to help you understand the options available when defining triggers.

    Note: If you get stuck along the way, scroll down to the Hints and Tips section at the end of this objective before turning to the lab guide or the solution video.

    Set Up the Trigger
    1. After completing the last objective, where you created a pre-trigger, you should be in the Azure portal with the trigger window open.
    2. Use the menu in Data Explorer to create a new trigger.
    3. Create a post-trigger to fire on any operation, and enter the following Id for your trigger: incrementOpsCounter.

      Note: If you don't supply this exact value for the Id, the SDK code that tests this trigger will not work.

    4. In the trigger body, change the generic function name to be the same as the trigger Id: incrementOpsCounter.
    Code the Trigger
    1. Using the following code as your guide, create a trigger that captures the item that was just created and increments the totalOperations property up by 1.
    2. Save (update) the trigger. This registers the trigger on the container.
    Sample Code

    Note: This code is only an example. It is not the exact code required to fulfill the objective, so do not copy/paste it and register it as your trigger; however, you can copy much of it into your trigger body and edit it to fulfill the requirements of the objective.

    function makeClone(){    
        var context = getContext();
        var container = context.getCollection();
        var response = context.getResponse();
        
        var createdItem = response.getBody();
        var createdItemLink = createdItem._self;
        var containerSelfLink = container.getSelfLink();
        
        var cylonCopy = createdItem;
        cylonCopy.sourceId = createdItem.id
        cylonCopy.id = (Math.floor(Math.random() * 1000000000000)).toString();
     
        var accept = container.createDocument(
            containerSelfLink,
            cylonCopy,
            function(err, itemReplaced) {
                        if(err) throw "Unable to create item; operation aborted";
            });
    
        if(!accept) throw "Unable to create item; operation aborted";
        return;         
                
    }
    

    Potential Quirks in the Portal User Interface

    • There may be a quirk in the portal UI, where the Save/Update feature is disabled after you have edited the trigger. If this happens, just make a minor edit in the Id control, and then edit it back to the original value. This action should wake up the button for you to save your work.
    • In a separate issue, if the UI throws an error when you save or update the trigger, close the trigger blade (tab) and re-open the trigger listed in the Data Explorer under the container name. It should then show that you actually did successfully save the trigger.

    Tips and Hints

    • If you copy/paste the sample code, make sure you retain the function name you entered in one of the previous steps of this objective.
    • Don't forget to save your work after updating the trigger code.
    • Take note where errors are explicitly thrown in the sample code; this aids in running the code in a single transaction with the container operation that triggered it.
  4. Challenge

    Run SDK Code to Add an Item and Fire Triggers

    In this objective, you will test your triggers. Triggers do not run automatically with database operations; they are called as an option when working with items in the Cosmos DB SDK.

    1. Re-open the Cloud Shell.
    2. The Program.cs file provides an example of how to call triggers for an item insert operation. The primary connection string should be copied and pasted in the Program.cs file to assign that value to the connString variable. If you have not completed this step, do that now by reviewing the instructions in the first objective.
    3. Skim the rest of the code to understand what it is doing. Notice that the sample item that is going to be inserted does not include the totalOperations property.
    4. At the command prompt, build the code. Assuming it builds without error, run the code.
    5. Assuming the code runs successfully, go back to the Data Explorer in the Azure portal and run a SQL query on the container called LabContainer. You should see a sample document in the container with the totalOperations property included in the item and set to a value of 1. This accurately represents the single insert operation conducted on that item.

    Tips and Hints

    • If the Cloud Shell times out before you return to it, you do not lose any updates you made to the Program.cs file; however, when the Cloud Shell restarts, you will need to change the directory back to the working directory for the Program.cs file. See the last step in the Housekeeping objective.
    • The command to build a .Net C# project is dotnet build and the command to run the code is dotnet run.
    • If you want to test just the pre-trigger, comment out the post-trigger in the ItemRequestOptions code block, and remove the comma after the reference to the pre-trigger. Save, build, and run the code. The totalOperations property on the new item will be set to 0 (zero), which is what happens in a successfully running pre-trigger.
    • If you want to test just the post-trigger, comment out the pre-trigger in the ItemRequestOptions code block. Save, build, and run the code. If you used the solution code from the lab guide, the totalOperations property will be set to null because the incrementing JavaScript code does not assign a default value to the property if it does not previously exist or has a non-integer value assigned. In our test, if the pre-trigger does not run, then the property does not exist: 1 + null = null. We chose to leave it this way in the solution code because we could imagine that this would help troubleshoot when a pre-trigger or other insert code is not behaving as expected. If you chose to handle it differently in your code, then the returned query results may look different in this post-trigger only test.
    • After running isolated tests on each of the two triggers, don't forget to restore the comma between the two lines of code.
    • Feel free to alter the SDK code to perform a replace/upsert operation to further test your triggers.

The Cloud Content team comprises subject matter experts hyper focused on services offered by the leading cloud vendors (AWS, GCP, and Azure), as well as cloud-related technologies such as Linux and DevOps. The team is thrilled to share their knowledge to help you build modern tech solutions from the ground up, secure and optimize your environments, and so much more!

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.

Start learning by doing today

View Plans