예제 #1
0
        /// <summary>
        /// Define GroupBy optimization (try re-use index)
        /// </summary>
        private void DefineGroupBy()
        {
            if (_query.GroupBy == null)
            {
                return;
            }

            if (_query.OrderBy != null)
            {
                throw new NotSupportedException("GROUP BY expression do not support ORDER BY");
            }
            if (_query.Includes.Count > 0)
            {
                throw new NotSupportedException("GROUP BY expression do not support INCLUDE");
            }

            var groupBy = new GroupBy(_query.GroupBy, _queryPlan.Select.Expression, _query.Having);
            var orderBy = (OrderBy)null;

            // if groupBy use same expression in index, set group by order to MaxValue to not run
            if (groupBy.Expression.Source == _queryPlan.IndexExpression)
            {
                // great - group by expression are same used in index - no changes here
            }
            else
            {
                // create orderBy expression
                orderBy = new OrderBy(groupBy.Expression, Query.Ascending);
            }

            _queryPlan.GroupBy = groupBy;
            _queryPlan.OrderBy = orderBy;
        }
예제 #2
0
        /// <summary>
        /// YieldDocuments will run over all key-ordered source and returns groups of source
        /// </summary>
        private IEnumerable <BsonDocument> YieldDocuments(BsonValue key, IEnumerator <BsonDocument> enumerator, GroupBy groupBy, Done done)
        {
            yield return(enumerator.Current);

            while (done.Running = enumerator.MoveNext())
            {
                var current = groupBy.Expression.ExecuteScalar(enumerator.Current);

                if (key == current)
                {
                    // yield return document in same key (group)
                    yield return(enumerator.Current);
                }
                else
                {
                    groupBy.Select.Parameters["key"] = current;

                    // stop current sequence
                    yield break;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// GROUP BY: Apply groupBy expression and aggregate results in DocumentGroup
        /// </summary>
        private IEnumerable <DocumentGroup> GroupBy(IEnumerable <BsonDocument> source, GroupBy groupBy)
        {
            using (var enumerator = source.GetEnumerator())
            {
                var done = new Done {
                    Running = enumerator.MoveNext()
                };

                while (done.Running)
                {
                    var key = groupBy.Expression.ExecuteScalar(enumerator.Current);

                    groupBy.Select.Parameters["key"] = key;

                    var group = YieldDocuments(key, enumerator, groupBy, done);

                    yield return(new DocumentGroup(key, enumerator.Current, group, _lookup));
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Run Select expression over a group source - each group will return a single value
        /// If contains Having expression, test if result = true before run Select
        /// </summary>
        private IEnumerable <BsonDocument> SelectGroupBy(IEnumerable <DocumentGroup> groups, GroupBy groupBy)
        {
            var defaultName = groupBy.Select.DefaultFieldName();

            foreach (var group in groups)
            {
                // transfom group result if contains select expression
                BsonValue value;

                try
                {
                    if (groupBy.Having != null)
                    {
                        var filter = groupBy.Having.ExecuteScalar(group, group.Root, group.Root);

                        if (!filter.IsBoolean || !filter.AsBoolean)
                        {
                            continue;
                        }
                    }

                    value = groupBy.Select.ExecuteScalar(group, group.Root, group.Root);
                }
                finally
                {
                    group.Dispose();
                }

                if (value.IsDocument)
                {
                    yield return(value.AsDocument);
                }
                else
                {
                    yield return(new BsonDocument {
                        [defaultName] = value
                    });
                }
            }
        }