text: // Tests the behavior of explain() when used with the aggregation pipeline and limits.
  // @tags: [do_not_wrap_aggregations_in_facets]
  (function() {
      "use strict";
  
      load("jstests/libs/analyze_plan.js");  // For getAggPlanStages().
  
      let coll = db.explain_limit;
  
      const kMultipleSolutionLimit = 101;
      const kCollSize = kMultipleSolutionLimit + 5;
      const kLimit = 10;
  
      // Return whether or explain() was successful and contained the appropriate fields given the
      // requested verbosity. Checks that the number of documents examined is correct based on
      // 'multipleSolutions', which indicates there was more than one plan available.
      function checkResults({results, verbosity, multipleSolutions}) {
          let cursorSubdocs = getAggPlanStages(results, "$cursor");
          assert.gt(cursorSubdocs.length, 0);
          for (let stageResult of cursorSubdocs) {
              assert(stageResult.hasOwnProperty("$cursor"));
              let result = stageResult.$cursor;
  
              assert.eq(result.limit, NumberLong(kLimit), tojson(results));
  
              if (verbosity === "queryPlanner") {
                  assert(!result.hasOwnProperty("executionStats"), tojson(results));
              } else {
                  // If it's "executionStats" or "allPlansExecution".
                  if (multipleSolutions) {
                      // If there's more than one plan available, we may run several of them against
                      // each other to see which is fastest. During this, our limit may be ignored
                      // and so explain may return that it examined more documents than we asked it
                      // to.
                      assert.lte(
                          result.executionStats.nReturned, kMultipleSolutionLimit, tojson(results));
                      assert.lte(result.executionStats.totalDocsExamined,
                                 kMultipleSolutionLimit,
                                 tojson(results));
                  } else {
                      assert.eq(result.executionStats.nReturned, kLimit, tojson(results));
                      assert.eq(result.executionStats.totalDocsExamined, kLimit, tojson(results));
                  }
              }
          }
      }
  
      // explain() should respect limit.
      coll.drop();
      assert.commandWorked(coll.createIndex({a: 1}));
  
      for (let i = 0; i < kCollSize; i++) {
          assert.writeOK(coll.insert({a: 1}));
      }
  
      const pipeline = [{$match: {a: 1}}, {$limit: kLimit}];
  
      let plannerLevel = coll.explain("queryPlanner").aggregate(pipeline);
      checkResults({results: plannerLevel, verbosity: "queryPlanner"});
  
      let execLevel = coll.explain("executionStats").aggregate(pipeline);
      checkResults({results: execLevel, verbosity: "executionStats", multipleSolutions: false});
  
      let allPlansExecLevel = coll.explain("allPlansExecution").aggregate(pipeline);
      checkResults(
          {results: allPlansExecLevel, verbosity: "allPlansExecution", multipleSolutions: false});
  
      // Create a second index so that more than one plan is available.
      assert.commandWorked(coll.createIndex({a: 1, b: 1}));
  
      plannerLevel = coll.explain("queryPlanner").aggregate(pipeline);
      checkResults({results: plannerLevel, verbosity: "queryPlanner"});
  
      execLevel = coll.explain("executionStats").aggregate(pipeline);
      checkResults({results: execLevel, verbosity: "executionStats", multipleSolutions: true});
  
      allPlansExecLevel = coll.explain("allPlansExecution").aggregate(pipeline);
      checkResults(
          {results: allPlansExecLevel, verbosity: "allPlansExecution", multipleSolutions: true});
  })();
  