@@ -123,7 +123,13 @@ def extra_where(self, compiler, connection): # noqa: ARG001
123123 raise NotSupportedError ("QuerySet.extra() is not supported on MongoDB." )
124124
125125
126- def join (self , compiler , connection , pushed_expressions = None ):
126+ def join (self , compiler , connection , pushed_expression = None ):
127+ """
128+ Generate a MongoDB $lookup stage for a join. Optionally accepts a pushed_expression,
129+ which is a filter expression involving fields from the joined collection, and
130+ can be pushed into the lookup pipeline for optimization.
131+ """
132+
127133 parent_template = "parent__field__"
128134
129135 def _get_reroot_replacements (expressions ):
@@ -182,12 +188,18 @@ def _get_reroot_replacements(expressions):
182188 extra .replace_expressions (replacements ).as_mql (compiler , connection )
183189 )
184190
185- if pushed_expressions and self .join_type == INNER :
186- rerooted_replacement = _get_reroot_replacements (pushed_expressions )
191+ # pushed_expression is a filter expression from the outer WHERE clause
192+ # that involves fields from the joined (right-hand) table and possibly the
193+ # outer (left-hand) table.
194+ # If it can be safely evaluated within the $lookup pipeline
195+ # (e.g., field comparisons like right.status = left.id), it is
196+ # "pushed down" into the join's $match stage to reduce the volume of
197+ # joined documents. This only applies to inner joins, as pushing
198+ # filters into a left join can change the semantics of the result.
199+ if pushed_expression and self .join_type == INNER :
200+ rerooted_replacement = _get_reroot_replacements (pushed_expression )
187201 extra_conditions .append (
188- pushed_expressions .replace_expressions (rerooted_replacement ).as_mql (
189- compiler , connection
190- )
202+ pushed_expression .replace_expressions (rerooted_replacement ).as_mql (compiler , connection )
191203 )
192204
193205 lookup_pipeline = [
0 commit comments