Detailed steps to reproduce the problem?
MongoDB compound indexes support per-field direction, but an Index declared with ordering expressions rather than field names either goes missing or aborts migrate, depending on what the index reports about itself.
A plain expression index is silently not created:
Index(F("priority").desc(), name="ordering_idx")
get_pymongo_index_model() returns None because contains_expressions is true. migrate reports success and the collection has no such index, so queries relying on it fall back to a collection scan.
An Index subclass which reports contains_expressions = False crashes instead. django_tasks_db.models.ConditionalPartialIndex does this deliberately, so that backends which under-report expression support still create the index. get_pymongo_index_model() then clears its own guard and reads fields_orders, which is empty for an expression index, so pymongo receives an empty key list:
File ".../django_mongodb_backend/schema.py", line 199, in add_index idx = index.get_pymongo_index_model(model, schema_editor=self, field=field) File ".../django_mongodb_backend/indexes.py", line 109, in get_pymongo_index_model return IndexModel(index_orders, name=self.name, **kwargs) File ".../pymongo/operations.py", line 789, in __init__ kwargs["key"] = _index_document(keys) File ".../pymongo/helpers_shared.py", line 185, in _index_document raise ValueError("key_or_list must not be empty") ValueError: key_or_list must not be empty
Both expressions above are orderings on a single field, which MongoDB indexes natively. The index django-tasks-db declares translates exactly, including its condition, which MySQL and SQLite cannot express:
{status: 1, priority: -1, run_after: 1, enqueued_at: 1}
partialFilterExpression: {status: {$eq: "READY"}}
Creating that index by hand and re-running the query gives an IXSCAN with no in-memory sort, so the translation is worth having rather than skipping.
Definition of done: what must be done to consider the task complete?
- F and OrderBy ordering expressions become compound index keys, ascending or descending per expression.
- An index holding an expression that can't be translated is skipped without raising.
- supports_expression_indexes reflects whatever subset is now supported.
- Tests cover a descending expression index, a mixed-direction compound one, and one that must still be skipped.
The exact Python version used, with patch level:
3.12.10 (v3.12.10:0cc81280367, Apr 8 2025, 08:46:59) [Clang 13.0.0 (clang-1300.0.29.30)]
The exact version of PyMongo used, with patch level:
4.17.0, has_c() True
Describe how MongoDB is set up. Local vs Hosted, version, topology, load balanced, etc.
Local standalone 8.0.29, started with MONGODB_VERSION=8.0 make run-server in drivers-evergreen-tools. Also reproduced on 8.2.12.
The operating system and version (e.g. Windows 7, OSX 10.8, ...)
macOS 26.6.2, arm64 (Darwin 25.6.0)
Web framework or asynchronous network library used, if any, with version (e.g. Django 1.7, mod_wsgi 4.3.0, gevent 1.0.1, Tornado 4.0.2, ...)
Django 6.1, django-mongodb-backend 6.1.0
- blocks
-
INTPYTHON-1083 Agree an approach for MongoDB support in django-tasks-db
-
- Backlog
-