/// <summary>
        /// Generates the query in explain mode
        /// </summary>
        /// <returns></returns>
        public string Explain()
        {
            string CollectionName = StartArgument.GetCollectionName();

            // Check if collection name is set
            // otherwise throw error
            if (string.IsNullOrWhiteSpace(CollectionName))
            {
                throw new InvalidOperationException("CollectionName cannot be empty");
            }

            // Setup results
            AlgebraOperatorResult Result = new AlgebraOperatorResult(new List <MongoDBOperator>());

            for (int i = 0; i < PipelineOperators.Count; i++)
            {
                AlgebraOperator Op = PipelineOperators[i];
                if (i == 0)
                {
                    Result.Commands.AddRange(Op.Run(StartMap).Commands);
                }
                else
                {
                    AlgebraOperator previousOp = PipelineOperators[i - 1];
                    Result.Commands.AddRange(Op.Run(previousOp.ComputeVirtualMap()).Commands);
                }
            }

            foreach (AlgebraOperator Op in PipelineOperators)
            {
                Result.Commands.AddRange(Op.Run(StartMap).Commands);
            }

            // Check if there are any commands to be executed last
            List <MongoDBOperator> MoveToEnd = Result.Commands.FindAll(C => C.ShouldExecuteLast);

            if (MoveToEnd.Count > 0)
            {
                Result.Commands.RemoveAll(C => C.ShouldExecuteLast);
                // Add again at the end
                Result.Commands.AddRange(MoveToEnd);
            }

            // Store command objects
            List <string> AggregatePipeline = new List <string>();

            foreach (MongoDBOperator Command in Result.Commands)
            {
                AggregatePipeline.Add(Command.ToJavaScript());
            }

            // TODO: Update this section to generate collection and aggregate
            // according to the query
            return(string.Format("db.{0}.explain('executionStats').aggregate([{1}], {{allowDiskUse: true}});", CollectionName, string.Join(",", AggregatePipeline)));
        }
        public string SummarizeToString()
        {
            string Ret = "S: " + StartArgument.SummarizeToString() + "\n";

            int i = 1;

            foreach (AlgebraOperator Op in PipelineOperators)
            {
                Ret += (i++) + ": " + Op.SummarizeToString() + "\n";
            }

            return(Ret);
        }
        /// <summary>
        /// Run the query generator
        /// </summary>
        /// <returns></returns>
        public string Run()
        {
            string CollectionName = StartArgument.GetCollectionName();

            // Check if collection name is set
            // otherwise throw error
            if (string.IsNullOrWhiteSpace(CollectionName))
            {
                throw new InvalidOperationException("CollectionName cannot be empty");
            }

            // Setup results
            AlgebraOperatorResult Result = new AlgebraOperatorResult(new List <MongoDBOperator>());

            // Get project arguments
            IEnumerable <ProjectArgument> attributesToProject = null;
            ProjectStage projStage = (ProjectStage)PipelineOperators.FirstOrDefault(Op => Op is ProjectStage);

            if (projStage != null)
            {
                attributesToProject = projStage.Arguments;
            }

            // Move SelectStage to start of array
            AlgebraOperator MoveToTop = PipelineOperators.Find(Op => Op is SelectStage2);

            if (MoveToTop != null)
            {
                PipelineOperators.Remove(MoveToTop);
                PipelineOperators.Insert(0, MoveToTop);
            }

            for (int i = 0; i < PipelineOperators.Count; i++)
            {
                AlgebraOperator Op = PipelineOperators[i];
                if (i == 0)
                {
                    Result.Commands.AddRange(Op.Run(StartMap, attributesToProject).Commands);
                }
                else
                {
                    AlgebraOperator previousOp = PipelineOperators[i - 1];
                    Result.Commands.AddRange(Op.Run(previousOp.ComputeVirtualMap(), attributesToProject).Commands);
                }
            }

            // Check if there are any commands to be executed last
            List <MongoDBOperator> MoveToEnd = Result.Commands.FindAll(C => C.ShouldExecuteLast);

            if (MoveToEnd.Count > 0)
            {
                Result.Commands.RemoveAll(C => C.ShouldExecuteLast);
                // Add again at the end
                Result.Commands.AddRange(MoveToEnd);
            }

            // Store command objects
            List <string> AggregatePipeline = new List <string>();

            foreach (MongoDBOperator Command in Result.Commands)
            {
                AggregatePipeline.Add(Command.ToJavaScript());
            }

            if (PrettyPrint)
            {
                return(string.Format("db.{0}.aggregate([{1}], {{allowDiskUse: true}}).pretty();", CollectionName, string.Join(",", AggregatePipeline)));
            }
            else
            {
                return(string.Format("db.{0}.aggregate([{1}], {{allowDiskUse: true}});", CollectionName, string.Join(",", AggregatePipeline)));
            }
        }