Skillversitas

Filtering Operators

MongoEngine translates Python keyword syntax into MongoDB query operators: field__op=value becomes {"field": {"$op": value}}. The double-underscore form keeps filters readable in code and composable across fields, and the full operator set covers comparison, membership, string matching, and field-existence tests. Combining filters uses Q objects with | (OR) and & (AND), and ~ negates an entire queryset.

The Operator Map

KwargMongo operatorMeaning
field=value-exact match (equality)
field__gt / __gte$gt / $gtegreater than (or equal)
field__lt / __lte$lt / $lteless than (or equal)
field__ne$nenot equal
field__in / __nin$in / $ninmembership / non-membership
field__contains / __icontainsregexsubstring, case (in)sensitive
field__startswith / __istartswithregexprefix match
field__endswith / __iendswithregex
field__exists$existskey present (True) or absent (False)
field__size$sizelist length
field__elemmatch$elemMatchlist element matching sub-conditions
from mongoengine import Document, StringField, IntField, ListField

class User(Document):
    username = StringField()
    age = IntField()
    roles = ListField(StringField())

User.objects(age__gte=18, age__lt=65)          # a range, both bounds
User.objects(roles__in=["admin", "editor"])    # has any of these roles
User.objects(roles__size=3)                    # exactly three roles
User.objects(username__istartswith="jo")       # case-insensitive prefix
User.objects(deleted_at__exists=False)         # not soft-deleted

Multiple kwargs are ANDed automatically: objects(a=1, b=2) matches documents where both hold. That is 90% of application querying.

OR Logic with Q Objects

from mongoengine import Q

# OR is not expressible as kwargs - use Q
User.objects(Q(age__lt=18) | Q(roles="admin"))

# complex nesting
User.objects(
    (Q(active=True) | Q(trial_ends__gt=datetime.now()))
    & Q(roles__nin=["banned"])
)

# negation of a whole queryset: "not (active is False)"
User.objects(~User.objects(active=False).filter(roles__in=["x"]))
active_or_trial = ~User.objects(active=False, trial_ends__lt=datetime.now())

The pattern to internalize: Q for OR and nesting, kwargs for AND, and ~ (inverted querysets) for "everything except". Chaining .filter() after a ~-queryset adds more AND conditions on top of the negation.

Filtering Into Lists and Subdocuments

class Post(Document):
    tags = ListField(StringField())
    author = EmbeddedDocumentField(Author)

Post.objects(tags="python")                    # any element equals
Post.objects(tags__all=["python", "web"])      # contains all listed
Post.objects(tags__elemmatch={"$gt": 0})       # custom sub-conditions
Post.objects(author__name="ada")               # dot-path into embedded docs

Equality against a list field matches any element (MongoDB semantics); __all and __elemmatch tighten it. Dot-path filters (author__name) reach into embedded documents - the embedded-documents chapter builds on this.

Regex Escaping

__contains and friends build a regex from your value, and MongoEngine escapes regex metacharacters in the input - so searching for "c++" matches literally, not as a pattern. When you want real regex power, pass a re.compile(...) object to a plain field= kwarg. The escape behavior is a feature: user-supplied search terms go through __icontains and cannot inject regex syntax.

Summary

Write filters as field__op kwargs (ANDed automatically), reach for Q objects the moment you need OR or nesting, use ~ to invert, and remember list-field equality means "any element". The operator map is short and stable - once __gte/__in/__icontains/__exists are habit, the filtering chapter of MongoEngine is effectively done, and the same conditions feed indexes and aggregation pipelines unchanged.