        void explain(OperationContext* opCtx,
                     ExplainOptions::Verbosity verbosity,
                     rpc::ReplyBuilderInterface* result) override {
            // Acquire locks. The RAII object is optional, because in the case of a view, the locks
            // need to be released.
            boost::optional<AutoGetCollectionForReadCommand> ctx;
            ctx.emplace(opCtx,
                        CommandHelpers::parseNsCollectionRequired(_dbName, _request.body),
                        AutoGetCollection::ViewMode::kViewsPermitted);
            const auto nss = ctx->getNss();

            // Parse the command BSON to a QueryRequest.
            const bool isExplain = true;
            auto qr =
                uassertStatusOK(QueryRequest::makeFromFindCommand(nss, _request.body, isExplain));

            // Finish the parsing step by using the QueryRequest to create a CanonicalQuery.
            const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
            const boost::intrusive_ptr<ExpressionContext> expCtx;
            auto cq = uassertStatusOK(
                CanonicalQuery::canonicalize(opCtx,
                                             std::move(qr),
                                             expCtx,
                                             extensionsCallback,
                                             MatchExpressionParser::kAllowAllSpecialFeatures));

            if (ctx->getView()) {
                // Relinquish locks. The aggregation command will re-acquire them.
                ctx.reset();

                // Convert the find command into an aggregation using $match (and other stages, as
                // necessary), if possible.
                const auto& qr = cq->getQueryRequest();
                auto viewAggregationCommand = uassertStatusOK(qr.asAggregationCommand());

                // Create the agg request equivalent of the find operation, with the explain
                // verbosity included.
                auto aggRequest = uassertStatusOK(
                    AggregationRequest::parseFromBSON(nss, viewAggregationCommand, verbosity));

                try {
                    uassertStatusOK(
                        runAggregate(opCtx, nss, aggRequest, viewAggregationCommand, result));
                } catch (DBException& error) {
                    if (error.code() == ErrorCodes::InvalidPipelineOperator) {
                        uasserted(ErrorCodes::InvalidPipelineOperator,
                                  str::stream() << "Unsupported in view pipeline: "
                                                << error.what());
                    }
                    throw;
                }
                return;
            }

            // The collection may be NULL. If so, getExecutor() should handle it by returning an
            // execution tree with an EOFStage.
            Collection* const collection = ctx->getCollection();

            // We have a parsed query. Time to get the execution plan for it.
            auto exec = uassertStatusOK(getExecutorFind(opCtx, collection, nss, std::move(cq)));

            auto bodyBuilder = result->getBodyBuilder();
            // Got the execution tree. Explain it.
            Explain::explainStages(exec.get(), collection, verbosity, &bodyBuilder);
        }
        void explain(OperationContext* opCtx,
                     ExplainOptions::Verbosity verbosity,
                     rpc::ReplyBuilderInterface* result) override {
             
             
            boost::optional<AutoGetCollectionForReadCommand> ctx;
            ctx.emplace(opCtx,
                        CommandHelpers::parseNsCollectionRequired(_dbName, _request.body),
                        AutoGetCollection::ViewMode::kViewsPermitted);
            const auto nss = ctx->getNss();

             
            const bool isExplain = true;
            auto qr =
                uassertStatusOK(QueryRequest::makeFromFindCommand(nss, _request.body, isExplain));

             
            const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
            const boost::intrusive_ptr<ExpressionContext> expCtx;
            auto cq = uassertStatusOK(
                CanonicalQuery::canonicalize(opCtx,
                                             std::move(qr),
                                             expCtx,
                                             extensionsCallback,
                                             MatchExpressionParser::kAllowAllSpecialFeatures));

            if (ctx->getView()) {
                 
                ctx.reset();

                 
                 
                const auto& qr = cq->getQueryRequest();
                auto viewAggregationCommand = uassertStatusOK(qr.asAggregationCommand());

                 
                 
                auto aggRequest = uassertStatusOK(
                    AggregationRequest::parseFromBSON(nss, viewAggregationCommand, verbosity));

                try {
                    uassertStatusOK(
                        runAggregate(opCtx, nss, aggRequest, viewAggregationCommand, result));
                } catch (DBException& error) {
                    if (error.code() == ErrorCodes::InvalidPipelineOperator) {
                        uasserted(ErrorCodes::InvalidPipelineOperator,
                                  str::stream() << "Unsupported in view pipeline: "
                                                << error.what());
                    }
                    throw;
                }
                return;
            }

             
             
            Collection* const collection = ctx->getCollection();

             
            auto exec = uassertStatusOK(getExecutorFind(opCtx, collection, nss, std::move(cq)));

            auto bodyBuilder = result->getBodyBuilder();
             
            Explain::explainStages(exec.get(), collection, verbosity, &bodyBuilder);
        }