Skip to content

Commit cd76b44

Browse files
committed
Move subquery lookup pipeline to query.
1 parent 08707e6 commit cd76b44

File tree

2 files changed

+40
-43
lines changed

2 files changed

+40
-43
lines changed

django_mongodb/expressions.py

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -95,57 +95,32 @@ def query(self, compiler, connection):
9595
subquery_compiler.parent_collections = {compiler.collection_name} | compiler.parent_collections
9696
columns = subquery_compiler.get_columns()
9797
field_name, expr = columns[0]
98-
result_query = subquery_compiler.query_class(subquery_compiler)
9998
subquery = subquery_compiler.build_query(
10099
columns
101100
if subquery_compiler.query.annotations or not subquery_compiler.query.default_cols
102101
else None
103102
)
104103
table_output = f"__subquery{len(compiler.subqueries)}"
105-
pipeline = subquery.get_pipeline()
106-
# the result must be a list of values. Se we compress the output
107-
if not self.has_limit_one():
108-
pipeline.extend(
109-
[
110-
{
111-
"$group": {
112-
"_id": None,
113-
"dummy_name": {"$addToSet": expr.as_mql(subquery_compiler, connection)},
114-
}
115-
},
116-
{"$project": {field_name: "$dummy_name"}},
117-
]
118-
)
119-
result_query.lookup_pipeline = [
120-
{
121-
"$lookup": {
122-
"from": self.get_meta().db_table,
123-
"pipeline": pipeline,
124-
"as": table_output,
125-
"let": {
126-
compiler.PARENT_FIELD_TEMPLATE.format(i): col.as_mql(compiler, connection)
127-
for col, i in subquery_compiler.column_mapping.items()
128-
},
129-
}
104+
subquery.lookup_data = {
105+
"as": table_output,
106+
"from": self.get_meta().db_table,
107+
"let": {
108+
compiler.PARENT_FIELD_TEMPLATE.format(i): col.as_mql(compiler, connection)
109+
for col, i in subquery_compiler.column_mapping.items()
130110
},
131-
{
132-
"$set": {
133-
table_output: {
134-
"$cond": {
135-
"if": {
136-
"$or": [
137-
{"$eq": [{"$type": f"${table_output}"}, "missing"]},
138-
{"$eq": [{"$size": f"${table_output}"}, 0]},
139-
]
140-
},
141-
"then": {},
142-
"else": {"$arrayElemAt": [f"${table_output}", 0]},
143-
}
111+
}
112+
# the result must be a list of values. Se we compress the output with an aggregation pipeline.
113+
if not self.has_limit_one():
114+
subquery.aggregation_pipeline = [
115+
{
116+
"$group": {
117+
"_id": None,
118+
"dummy_name": {"$addToSet": expr.as_mql(subquery_compiler, connection)},
144119
}
145-
}
146-
},
147-
]
148-
compiler.subqueries.append(result_query)
120+
},
121+
{"$project": {field_name: "$dummy_name"}},
122+
]
123+
compiler.subqueries.append(subquery)
149124
return f"${table_output}.{field_name}"
150125

151126

django_mongodb/query.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(self, compiler):
5656
self.aggregation_pipeline = compiler.aggregation_pipeline
5757
self.extra_fields = None
5858
self.combinator_pipeline = None
59+
self.lookup_data = None
5960

6061
def __repr__(self):
6162
return f"<MongoQuery: {self.mongo_query!r} ORDER {self.ordering!r}>"
@@ -95,6 +96,27 @@ def get_pipeline(self):
9596
pipeline.append({"$skip": self.query.low_mark})
9697
if self.query.high_mark is not None:
9798
pipeline.append({"$limit": self.query.high_mark - self.query.low_mark})
99+
if self.lookup_data:
100+
table_output = self.lookup_data["as"]
101+
pipeline = [
102+
{"$lookup": {**self.lookup_data, "pipeline": pipeline}},
103+
{
104+
"$set": {
105+
table_output: {
106+
"$cond": {
107+
"if": {
108+
"$or": [
109+
{"$eq": [{"$type": f"${table_output}"}, "missing"]},
110+
{"$eq": [{"$size": f"${table_output}"}, 0]},
111+
]
112+
},
113+
"then": {},
114+
"else": {"$arrayElemAt": [f"${table_output}", 0]},
115+
}
116+
}
117+
}
118+
},
119+
]
98120
return pipeline
99121

100122

0 commit comments

Comments
 (0)