Skip to content

CSHARP-5495: Support $concatArrays and $setUnion aggregation accumulators#2014

Open
papafe wants to merge 7 commits into
mongodb:mainfrom
papafe:csharp5495
Open

CSHARP-5495: Support $concatArrays and $setUnion aggregation accumulators#2014
papafe wants to merge 7 commits into
mongodb:mainfrom
papafe:csharp5495

Conversation

@papafe

@papafe papafe commented May 27, 2026

Copy link
Copy Markdown
Contributor

No description provided.

…tors

Map g.SelectMany(x => x.Arr) and g.SelectMany(x => x.Arr).Distinct() to
the new $concatArrays and $setUnion accumulators inside $group, $bucket
and $bucketAuto via two new pattern matches in AstGroupingPipelineOptimizer.

Add ConcatArrays and SetUnion extension methods on
ISetWindowFieldsPartitionExtensions for use inside $setWindowFields.
@papafe papafe added the feature Adds new user-facing functionality. label May 27, 2026
case "As": DeduceAsMethodSerializers(); break;
case "AsQueryable": DeduceAsQueryableMethodSerializers(); break;
case "Concat": DeduceConcatMethodSerializers(); break;
case "ConcatArrays": DeduceConcatArraysMethodSerializers(); break;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need unit-tests for these new supported methods.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added SerializerFinder unit tests for those.

papafe added 2 commits June 2, 2026 16:06
@papafe papafe marked this pull request as ready for review June 2, 2026 14:28
@papafe papafe requested a review from a team as a code owner June 2, 2026 14:28
@papafe papafe requested review from ajcvickers and Copilot June 2, 2026 14:28
@papafe papafe requested review from sanych-sun and removed request for ajcvickers June 2, 2026 14:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds LINQ3 translation support for MongoDB’s $concatArrays and $setUnion accumulators/window operators, including new window-partition extension methods, AST operator wiring, serializer inference, and integration tests for both $setWindowFields and grouping/bucket scenarios.

Changes:

  • Added ConcatArrays / SetUnion window-partition extension methods and reflection/translation plumbing to render $concatArrays and $setUnion.
  • Updated grouping pipeline optimizer to recognize SelectMany-shaped ASTs and rewrite them into $concatArrays / $setUnion accumulators.
  • Expanded test coverage for new operators in window and grouping/bucket contexts, plus serializer-finder expectations.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslatorTests.cs Adds window translation tests for $concatArrays and $setUnion.
tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SelectManyMethodToAggregationExpressionTranslatorTests.cs Adds grouping/bucket tests expecting $concatArrays/$setUnion accumulators; adjusts fixture data and existing tests.
tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/SerializerFinders/WindowTests.cs Adds serializer resolution coverage for new window methods.
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs Registers ConcatArrays/SetUnion as unary window methods and maps them to AST operators.
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConcatArraysMethodToAggregationExpressionTranslator.cs New method translator entry point delegating to window translation when applicable.
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SetUnionMethodToAggregationExpressionTranslator.cs New method translator entry point delegating to window translation when applicable.
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs Routes ConcatArrays/SetUnion method calls to the new translators.
src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs Adds serializer deduction logic for ConcatArrays/SetUnion window methods.
src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/WindowMethod.cs Adds WindowMethod.ConcatArrays and WindowMethod.SetUnion reflection bindings.
src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstGroupingPipelineOptimizer.cs Adds optimizer rewrites to turn SelectMany-shaped $reduce patterns into $concatArrays/$setUnion accumulators.
src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstUnaryWindowOperator.cs Adds renderable window operator enum values for $concatArrays/$setUnion.
src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstUnaryAccumulatorOperator.cs Adds renderable accumulator operator enum values for $concatArrays/$setUnion.
src/MongoDB.Driver/Linq/ISetWindowFieldsPartitionExtensions.cs Adds public LINQ window APIs: ConcatArrays and SetUnion.
src/MongoDB.Driver/Core/Misc/Feature.cs Introduces feature gate ConcatArraysAndSetUnionAccumulators (WireVersion.Server81).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +71 to +75
var expectedResult = new[] { 1, 10, 2, 20, 3, 30 };
foreach (var result in results)
{
result["Result"].AsBsonArray.Select(i => i.AsInt32).Should().BeEquivalentTo(expectedResult);
}
Comment on lines +473 to +481
public override AstNode VisitReduceExpression(AstReduceExpression node)
{
// { $reduce : { input : { $map : { input : "$_elements", as : "x", in : f(x) } }, initialValue : [], in : { $concatArrays : ["$$value", "$$this"] } } }
// => { __agg0 : { $concatArrays : f(x => element) } } + "$__agg0"
if (IsSelectManyShapeOverElements(node, out var rewrittenArg))
{
var accumulatorExpression = AstExpression.UnaryAccumulator(AstUnaryAccumulatorOperator.ConcatArrays, rewrittenArg);
return CreateGetAccumulatorFieldExpression(accumulatorExpression);
}
Comment on lines +499 to +507
// { $setUnion : { $reduce : { input : { $map : { input : "$_elements", as : "x", in : f(x) } }, initialValue : [], in : { $concatArrays : ["$$value", "$$this"] } } } }
// => { __agg0 : { $setUnion : f(x => element) } } + "$__agg0"
if (node.Operator == AstUnaryOperator.SetUnion &&
node.Arg is AstReduceExpression setUnionReduceArg &&
IsSelectManyShapeOverElements(setUnionReduceArg, out var setUnionArg))
{
var accumulatorExpression = AstExpression.UnaryAccumulator(AstUnaryAccumulatorOperator.SetUnion, setUnionArg);
return CreateGetAccumulatorFieldExpression(accumulatorExpression);
}
papafe added 4 commits June 3, 2026 12:16
The grouping/bucket SelectMany rewrite into $concatArrays/$setUnion accumulators requires server 8.1. Since that query shape was already translatable (as $push + $reduce, which runs on any server), emit the accumulator form only when the compatibility level supports it; otherwise keep the $reduce fallback. The $setWindowFields window methods are new API and stay unconditional.
- Add missing closing brace in SelectMany_Distinct_in_BucketAuto else-branch expected stage
- Assert exact UniqueTags contents instead of only HaveCount
- Reorder ConcatArrays/SetUnion alphabetically in WindowMethod and unary overload set

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Comment on lines +567 to +579
private bool IsSelectManyShapeOverElements(AstReduceExpression node, out AstExpression rewrittenArg)
{
if (IsMappedElementsField(node.Input, out var mappedArg) &&
IsEmptyArrayConstant(node.InitialValue) &&
IsConcatArraysOfValueAndThis(node.In))
{
rewrittenArg = mappedArg;
return true;
}

rewrittenArg = null;
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Adds new user-facing functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants