MongoEngine: Set min/max for a number field

Updated: February 10, 2024 By: Guest Contributor Post a comment

Introduction

MongoEngine, an Object-Document Mapper (ODM) for working with MongoDB from Python, offers a convenient way to interact with MongoDB. This tutorial will guide you through setting minimum and maximum values for numerical fields in MongoEngine to ensure your data adheres to expected constraints.

Starting with the Basics

Before diving into min/max constraints, let’s ensure we have a clear understanding of how to define a document in MongoEngine.

from mongoengine import Document, FloatField

class Employee(Document):
    salary = FloatField()

In the example above, we’ve defined an Employee model with a salary field of type FloatField.

Setting Min and Max Values

Here’s how you implement minimum and maximum value constraints:

from mongoengine import Document, FloatField

class Employee(Document):
    salary = FloatField(min_value=30000.0, max_value=200000.0)

This ensures that any salary value outside the range of 30,000 to 200,000 will raise a validation error when you attempt to save an Employee document.

Dynamic Min/Max Values

In some scenarios, you might want the min/max constraints to be dynamic. Here’s how you can achieve this:

from mongoengine import Document, FloatField, signals

class Employee(Document):
    salary = FloatField()

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        if document.salary < document.min_salary() or document.salary > document.max_salary():
            raise Exception('Salary must be between minimum and maximum values.')

    def min_salary(self):
        return 30000.0

    def max_salary(self):
        return 200000.0

signals.pre_save.connect(Employee.pre_save, sender=Employee)

This method employs signals to check the constraints right before saving the document, allowing for more flexibility in defining min_salary and max_salary.

Custom Validation Logic

Sometimes, min/max checks need additional logic. You might, for example, want different limits based on another field such as job_title:

from mongoengine import Document, FloatField, StringField

class Employee(Document):
    salary = FloatField()
    job_title = StringField()

    def clean(self):
        if self.job_title == 'Manager' and (self.salary < 50000.0 or self.salary > 250000.0):
            raise ValueError('Invalid salary for manager.')
        elif self.job_title != 'Manager' and (self.salary < 30000.0 or self.salary > 200000.0):
            raise ValueError('Invalid salary for this job title.')

The clean method offers a way to incorporate complex validation logic, ensuring the data complies with our business rules.

Utilizing Min/Max Values in Queries

MongoEngine doesn’t restrict using min and max values to field definitions alone; you can also leverage these constraints in your queries:

employees = Employee.objects(salary__gte=30000, salary__lte=200000)

This query fetches Employee documents with salaries within the specified range, demonstrating how MongoEngine supports complex querying operations in a syntactically clear way.

Handling Validation Errors

When a document fails validation due to min/max constraints, MongoEngine raises a ValidationError. Catching and handling these exceptions ensures that your application can provide informative feedback to users:

try:
    employee = Employee(salary=250000.0).save()
except ValidationError as e:
    print(f'Error: {e.message}')

To effectively prevent data integrity issues, it’s critical to understand and apply proper error handling tactics when working with MongoEngine documents.

Conclusion

Setting minimum and maximum values for numeric fields in MongoEngine helps enforce data integrity and business rules. Starting with basic constraints and progressing to dynamic validation and complex logic demonstrates MongoEngine’s flexibility and power in managing MongoDB documents with Python.