Skip to content

Commit 3f304a6

Browse files
committed
edits
1 parent bc3697d commit 3f304a6

File tree

2 files changed

+28
-29
lines changed

2 files changed

+28
-29
lines changed

django_mongodb_backend/compiler.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -550,24 +550,25 @@ def get_combinator_queries(self):
550550

551551
def get_lookup_pipeline(self):
552552
result = []
553+
# To improve join performance, push conditions (filters) from the
554+
# WHERE ($match) clause to the JOIN ($lookup) clause.
553555
where = self.get_where()
554-
promote_filters = defaultdict(list)
556+
pushed_filters = defaultdict(list)
555557
for expr in where.children if where and where.connector == AND else ():
556558
# Only basic lookups are pushed, no subqueries or complex
557-
# conditions. To avoid duplication across subqueries,
558-
# only the LHS target table is used.
559+
# conditions. To avoid duplication across subqueries, only the LHS
560+
# target table is used.
559561
if (
560562
isinstance(expr, Lookup)
561563
and isinstance(expr.lhs, Col)
562564
and (is_direct_value(expr.rhs) or isinstance(expr.rhs, Value | Col))
563565
):
564-
promote_filters[expr.lhs.alias].append(expr)
565-
566+
pushed_filters[expr.lhs.alias].append(expr)
566567
for alias in tuple(self.query.alias_map):
567568
if not self.query.alias_refcount[alias] or self.collection_name == alias:
568569
continue
569570
result += self.query.alias_map[alias].as_mql(
570-
self, self.connection, WhereNode(promote_filters[alias], connector=AND)
571+
self, self.connection, WhereNode(pushed_filters[alias], connector=AND)
571572
)
572573
return result
573574

django_mongodb_backend/query.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ 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_expression=None):
127-
"""
128-
Generate a MongoDB $lookup stage for a join. Optionally accepts a
129-
pushed_expression, which is a filter expression involving fields from the
130-
joined collection, and can be pushed into the lookup pipeline for
131-
optimization.
126+
def join(self, compiler, connection, pushed_filter_expression=None):
132127
"""
128+
Generate a MongoDB $lookup stage for a join.
133129
130+
`pushed_filter_expression` is a Where expression involving fields from the
131+
joined collection which can be pushed from the WHERE ($match) clause to the
132+
JOIN ($lookup) clause to improve performance.
133+
"""
134134
parent_template = "parent__field__"
135135

136136
def _get_reroot_replacements(expression):
@@ -176,34 +176,32 @@ def _get_reroot_replacements(expression):
176176
self.parent_alias, lhs, compiler.collection_name, rhs
177177
)
178178
lhs_fields.append(lhs.as_mql(compiler, connection))
179-
# In the lookup stage, the reference to this column doesn't include
180-
# the collection name.
179+
# In the lookup stage, the reference to this column doesn't include the
180+
# collection name.
181181
rhs_fields.append(rhs.as_mql(compiler, connection))
182182
# Handle any join conditions besides matching field pairs.
183183
extra = self.join_field.get_extra_restriction(self.table_alias, self.parent_alias)
184-
185184
extra_conditions = []
186185
if extra:
187186
replacements = _get_reroot_replacements(extra)
188187
extra_conditions.append(
189188
extra.replace_expressions(replacements).as_mql(compiler, connection)
190189
)
191-
192-
# pushed_expression is a filter expression from the outer WHERE clause
193-
# that involves fields from the joined (right-hand) table and possibly the
194-
# outer (left-hand) table.
195-
# If it can be safely evaluated within the $lookup pipeline
196-
# (e.g., field comparisons like right.status = left.id), it is
197-
# "pushed down" into the join's $match stage to reduce the volume of
198-
# joined documents. This only applies to inner joins, as pushing
199-
# filters into a left join can change the semantics of the result.
200-
# LEFT JOINs may rely on null checks to detect missing RHS.
201-
if pushed_expression and self.join_type == INNER:
202-
rerooted_replacement = _get_reroot_replacements(pushed_expression)
190+
# pushed_filter_expression is a filter expression from the outer WHERE
191+
# clause that involves fields from the joined (right-hand) table and
192+
# possibly the outer (left-hand) table. If it can be safely evaluated
193+
# within the $lookup pipeline (e.g., field comparisons like
194+
# right.status = left.id), it is "pushed" into the join's $match stage to
195+
# reduce the volume of joined documents. This only applies to INNER JOINs,
196+
# as pushing filters into a LEFT JOIN can change the semantics of the
197+
# result. LEFT JOINs may rely on null checks to detect missing RHS.
198+
if pushed_filter_expression and self.join_type == INNER:
199+
rerooted_replacement = _get_reroot_replacements(pushed_filter_expression)
203200
extra_conditions.append(
204-
pushed_expression.replace_expressions(rerooted_replacement).as_mql(compiler, connection)
201+
pushed_filter_expression.replace_expressions(rerooted_replacement).as_mql(
202+
compiler, connection
203+
)
205204
)
206-
207205
lookup_pipeline = [
208206
{
209207
"$lookup": {

0 commit comments

Comments
 (0)