Query
Querying Documents
Writing queries for selecting MongoDB data is easy. Querying in Djongo works exactly like in Django because Djongo translates Django’s ORM queries into MongoDB queries under the hood. You interact with your data using model managers and QuerySets, which are lazy, iterable representations of database queries.
A QuerySet is constructed when you call methods like .all() or .filter(),
and only hits the database when you actually evaluate it.
This design allows you to build queries incrementally without immediately hitting the database.
QuerySets make it easy to reason about database access while writing clean Python code.
qs = Entry.objects.all()
Retrieving Objects
The most common methods to retrieve data are .all(), .get(), and .filter().
.all()returns every record as a QuerySet..get()returns a single object and raises an error if none or multiple match..filter()returns a QuerySet matching given conditions.
Filters use field lookups expressed with double underscores (e.g. field__lookup=value) and are
injection safe because Django escapes parameters.
post = Entry.objects.get(id=1)
recent_posts = Entry.objects.filter(published_date__year=2024)
Chaining Filters and Field Lookups
You can chain filters to build complex queries. Each filter call returns a new QuerySet,
allowing you to progressively narrow down results.
Django supports lookups like exact, iexact, contains, icontains,
gte, lte, in, and range.
QuerySets remain lazy until evaluated, so chaining does not hit the database immediately. This pattern allows for clean, readable, composable queries.
qs = Entry.objects.filter(published_date__year=2024)\
.filter(title__icontains="djongo")\
.order_by('-published_date')
Ordering, Slicing, and Limiting
You can order results using .order_by() and limit them using Python slicing syntax.
Ordering accepts one or more field names, with a - prefix for descending order.
Slicing translates to SQL/MongoDB LIMIT and OFFSET.
You can also use .first() and .last() to get a single record or None if none exist.
These tools let you fetch only the portion of data you need efficiently.
latest_five = Entry.objects.order_by('-published_date')[:5]
first_post = Entry.objects.order_by('published_date').first()
Aggregations and Related Lookups
Django ORM (and therefore Djongo) supports aggregations with functions like Count,
Sum, Avg, Min, and Max. Use .aggregate() to return a single summary value,
or .annotate() to add computed values to each result row.
You can traverse related
fields using double underscores (following ForeignKey, OneToOneField, or ManyToManyField).
This lets you perform joins and calculations without writing raw database queries.
from djongo.models import Count
authors = Author.objects.annotate(num_posts=Count('post'))
for a in authors:
print(a.name, a.num_posts)
Evaluating QuerySets
A QuerySet executes when it’s evaluated — when you iterate over it, convert it to a list,
access a slice, or call .count(), .exists(), .first(), or .last().
The results are cached after the first evaluation,
so repeated iterations don’t hit the database again unless you call .all() to refresh.
This lazy and cached behavior helps minimize database traffic and improve performance.
You can learn more about making queries here.
qs = Entry.objects.filter(published_date__year=2024)
print(list(qs)) # Executes the query
print(list(qs)) # Uses the cached results, no new query
Querying Embedded fields
To query all BlogPost with content made by authors whose name startswith Beatles use the following query:
entries = Entry.objects.filter(blog__startswith={'name': 'Beatles'})
Internally Djongo converts this query (for BlogPost collection) to the form:
filter = {
'blog.name': {
'$regex': '^Beatles.*$'
}
}
For querying nested embedded fields provide the appropriate dictionary value
entries = Entry.objects.filter(blog__startswith={'tagline': {'subtitle': 'Artist'}})
Internally Djongo converts this query (for BlogPost collection) to the form:
filter = {
'blog.tagline.subtitle': {
'$regex': '^Artist.*$'
}
}
Querying Array fields
Djongo uses a mixture of Django query syntax and MongoDB query syntax. Consider a query to retrieve all entries made by the author Paul. Using ManyToManyField this requires 2 SQL queries. First selects the id for author Paul from the author table. Next, a JOIN with entry_authors and entry gives the corresponding entries.
With ArrayField the query reduces to a single simple query:
entries = Entry.objects.filter(authors={'name': 'Paul'})
Djongo lets you get even more specific with your queries. To query all entries where the third author is Paul:
entries = Entry.objects.filter(authors={'2.name': 'Paul'})
Note: In MongoDB the first element in the array starts at index 0.
Text Search
Djongo lets you run MongoDB text search queries on Django CharField and TextField. To run a text search, use the text_search operator that comes built in with Djongo.
from djongo.models.indexes import TextIndex
from djongo import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
class Meta:
indexes = [
TextIndex(fields=['name'])
]
Blog.objects.filter(name__text_search='Paul Lennon')
This will generate the pymongo command:
db.blog.find( { '$text': { '$search': "Paul Lennon" } } )
Geospatial Queries
Geospatial queries are carried out in Djongo by using a combination of the near lookup operator and the Near search object.
class Near:
def __init__(self,
type=None,
coordinates=None,
minDistance=None,
maxDistance=None):
Example
from djongo.models.indexes import TwoDSphereIndex
from djongo import models
class Location(models.Model):
type = models.CharField(max_length=100)
coordinates = models.ArrayField()
class Meta:
abstract = True
class Entry(models.Model):
loc = models.EmbeddedField(
model_container=Location,
)
class Meta:
indexes = [
TwoDSphereIndex(fields=['loc'])
]
from djongo.models import Near
search_region = Near(
type='point',
coordinates=[-33.9, 89.81],
minDistance=100,
maxDistance=200
)
Entry.objects.filter(loc__near=search_region)
This generates the following pymongo search query:
db.entry.find({
'loc':
{ '$near':
{
'$geometry': { 'type': "Point", 'coordinates': [-33.9, 89.81] },
'$minDistance': 100,
'$maxDistance': 200
}
}
})
Specifying Query Options
Djongo lets you specify the configuration of the find command into your QuerySets. Call the configure method on a QuerySet to configure the find query. All options supported by aggregate or find can be included as kwargs. Example of valid arguments:
Arguments
| Argument | Type | Description |
|---|---|---|
allowDiskUse | boolean | Enables writing to temporary files |
collation | Collation | Used to specify the collation. Takes an instance of Collation |
Example
Blog.objects.filter(name='John Lennon').configure(hint=['-tagline'])
This generates the following pymongo find query:
db.blog.find({'name': 'John Lennon'}, hint=[('tagline', pymongo.DESCENDING)])
Tailable Cursors
Tailable cursors are used to retrieve data from capped collections. The querySet first has to be configured using configure to use a tailable cursor in the pymongo find command.
Results of the querySet can only be accessed by generating an iterator by calling the QuerySet iterator
Example
iterable = Blog.objects.filter(name='John').configure(cursor_type=CursorType.TAILABLE).iterator()
for blog in iterable:
blog.name
