Introduction to CouchDB with .NET part 13: validation functions in design documents

Introduction

In the previous post we saw some additional examples of MapReduce functions in CouchDB view design documents. First we investigated the built-in _sum reducer which – as its name applies – can be used to sum up numerical values of the keys from the map phase. The reducer can sum up integers, arrays of integers and objects whose properties are integers. Then we looked at how grouping works and then continued with a brief discussion of custom reducers. We can write our own reducers in JavaScript but we need to make sure that we always return a single value. If we need multiple values from a reducer then can wrap them in a JSON object and return that. Also, the usage of the rereduce parameter is confusing at first and we might only need it in large data sets.

In this post we’ll take a look at another type of functions in design documents, namely validation functions.

Validation functions

A validation function is most often used to validate a modification in the data set. It is called automatically when a new document is added to the database or an existing one is updated. The validation function can check if a certain field is present, if its value is reasonable based on our business logic or if the user is authorised to perform the modification.

Validation functions are enclosed within the same type of design documents as views which we’ve looked at before in this series. Views are denoted by the “views” keyword. Similarly, a validation function is declared using the validate_doc_update property in the design document. Note that there can be only one validation function in a design document.

Demo

For the demo create a new database in Fauxton or via the HTTP API as you wish. Call the database “results”. Then select to add a new design document with the following JSON object:

{
  "_id": "_design/validation",
  "validate_doc_update": "function(newDocument, oldDocument, userContext) { if (!newDocument.points || !newDocument.name) throw({forbidden: 'The points and name fields are compulsory'})  }"
}

This is a design document, like the ones we’ve seen up to now so we still adhering to the ID naming rule and start the ID name with “_design”. Then we have the validation function which consists of the following elements:

  • newDocument: this is the new document about to be inserted or meant as an update of an existing document
  • oldDocument: this is the document that’s being updated
  • userContext: the user context to check if a user is allowed to execute the modification. This object includes the properties “name” and “roles” where roles is a string array. We can check if the user has the required role to perform the modification. We’ll look into security later on in this series.
  • The function body: we check if the new document has the required properties “points” and “name”. If either of them is missing then we throw a forbidden exception with an error message. Exception types can be either “forbidden” or “unauthorized”

Now try to insert the following document:

{
  "name": "John"
}

It will fail and Fauxton UI will show the following message:

Document insertion failed in CouchDB Fauxton UI due to validation function

Next add a valid document:

{
  "name": "John",
  "points": 40
}

The update function works with updates as well. Remove the “name” property from John and try to update the document. It will result in the same exception message.

Let’s extend the validation function with some more checks:

"validate_doc_update": "function(newDocument, oldDocument, userContext) { if (!newDocument.points || !newDocument.name) { throw({forbidden: 'The points and name fields are compulsory'});} if (newDocument.points < 1) { throw({forbidden: 'The points value must be positive'});  }if (oldDocument != null && oldDocument.points > newDocument.points) {        throw({forbidden: 'Points cannot decrease'});    }  }"

That’s not a pretty sight so I’ll break out the function separately for easier viewing:

function(newDocument, oldDocument, userContext) { 
	if (!newDocument.points || !newDocument.name) { 
		throw({forbidden: 'The points and name fields are compulsory'});
	} 
	
	if (newDocument.points < 1) { 
		throw({forbidden: 'The points value must be positive'});  
	}
	
	if (oldDocument != null && oldDocument.points > newDocument.points) { 
		throw({forbidden: 'Points cannot decrease'});    
	}  
}

So we have two new validation steps:

  • The first one checks if the points entered is at least 1
  • The second one is an example of how we can use the existing document for validation. This rule says that the number of points cannot decrease with an update. We compare the points in the old document and the points in the new document and throw an exception if there’s a decrease

Go ahead and test these cases in Fauxton. You should see exception messages similar to the following:

No negative values are allowed due to validation function in CouchDB

Points not allowed to decrease due to validation function in CouchDB

I think this is a really good function similar to triggers in relational databases.

Read the next part here.

You can view all posts related to data storage on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

One Response to Introduction to CouchDB with .NET part 13: validation functions in design documents

  1. Pingback: CouchDB Weekly News, June 15, 2017 – CouchDB Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: