diff --git a/world_cup/views.py b/world_cup/views.py index f1409f0..eecb738 100644 --- a/world_cup/views.py +++ b/world_cup/views.py @@ -54,6 +54,23 @@ def top_scorers(request): }, } +def _get_query(queryset): + """Print the collection and aggregation pipeline behind `queryset`.""" + if isinstance(queryset, RawQuerySet): + # raw_aggregate() pipelines are already MQL: RawQuery has no compiler, + # it just holds the pipeline that gets handed to collection.aggregate(). + collection = queryset.model._meta.db_table + pipeline = queryset.query.pipeline + else: + compiler = queryset.query.get_compiler(using=queryset.db) + # Same steps the backend takes in SQLCompiler.as_sql()/explain_query(). + compiler.pre_sql_setup() + # The compiler needs the columns to project. + columns = compiler.get_project_columns(compiler.columns) + mongo_query = compiler.build_query(columns) + collection = compiler.collection_name + pipeline = mongo_query.get_pipeline() + return f'db.world_cup_match.aggregate({pipeline})' def _execute_query(query_text): """Parse and execute a user query, return result dict.""" @@ -66,6 +83,7 @@ def _execute_query(query_text): .aggregate(tournament_goals=Sum("total_goals")) ) return { + "query": _get_query(result), "results": [{"tournament_goals": result["tournament_goals"] or 0}], } @@ -79,6 +97,7 @@ def _execute_query(query_text): ] results = Match.objects.raw_aggregate(pipeline) return { + "query": _get_query(results), "results": [{"scorer": r.pk, "goals": r.total_goals} for r in results], } @@ -87,7 +106,7 @@ def _execute_query(query_text): from django.db.models import Q matches = Match.objects.filter(Q(team1__iexact=team) | Q(team2__iexact=team)).order_by("date") return { - "query": f'db.world_cup_match.aggregate([{{$match: {{$or: [{{team1: {{$regex: "^{team}$", $options: "i"}}}}, {{team2: {{$regex: "^{team}$", $options: "i"}}}}]}}}}, {{$sort: {{date: 1}}}}])', + "query": _get_query(matches), "results": [ { "date": str(m.date), @@ -104,7 +123,7 @@ def _execute_query(query_text): round_name = query_text.strip()[6:].strip() matches = Match.objects.filter(round__icontains=round_name).order_by("date") return { - "query": f'db.world_cup_match.aggregate([{{$match: {{round: {{$regex: "{round_name}", $options: "i"}}}}}}, {{$sort: {{date: 1}}}}])', + "query": _get_query(matches), "results": [ { "date": str(m.date), @@ -128,6 +147,7 @@ def _execute_query(query_text): ] results = Match.objects.raw_aggregate(pipeline) return { + "query": _get_query(results), "results": [{"round": r.pk, "goals": r.total_goals, "matches": r.matches} for r in results], } @@ -150,4 +170,4 @@ def query_shell(request): context["mongo_query"] = result.get("query", "") context["results"] = result.get("results", []) - return render(request, "world_cup/shell.html", context) \ No newline at end of file + return render(request, "world_cup/shell.html", context)