ExportXMLWordPrintableJSON

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: django
    • None
    • None
    • Python Drivers
    • None
    • None
    • None
    • None
    • None
    • None

      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

            Assignee:
            Unassigned
            Reporter:
            Steve Silvester
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: