Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSHARP-5436: Optimize special case of Any with constant array and fie… #1585

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

sanych-sun
Copy link
Member

…ld equals parameter in predicate

@sanych-sun sanych-sun requested a review from rstam January 4, 2025 01:28
@sanych-sun sanych-sun requested a review from a team as a code owner January 4, 2025 01:28
@@ -103,6 +103,50 @@ static bool OperatorMapsNullToNull(AstUnaryOperator @operator)
}
}

public override AstNode VisitExprFilter(AstExprFilter node)
{
var optimizedNode = (AstExprFilter)base.VisitExprFilter(node);
Copy link
Member Author

Choose a reason for hiding this comment

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

Decided to visit upfront, for easier handling of nested documents scenario.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it safe to assume base.VisitExprFilter always returns an AstExprFilter? I guess looking at the source code we can convince ourselves that it does.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Even if it always returns VisitExprFilter for now, it's better to double-check.

mapExpression.In is AstBinaryExpression inBinaryExpression &&
inBinaryExpression.Operator == AstBinaryOperator.Eq &&
TryGetBinaryExpressionArguments(inBinaryExpression, out AstFieldPathExpression fieldPathExpression, out AstVarExpression varExpression) &&
fieldPathExpression.Path.Length > 1 && fieldPathExpression.Path[0] == '$' && fieldPathExpression.Path[1] != '$' &&
Copy link
Member Author

Choose a reason for hiding this comment

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

Should we have some more elegant way to check if fieldPath points to the "current" variable?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what you mean.

But anything that starts with $$ is not a field so I think that's all we need to check.


return optimizedNode;

static bool TryGetBinaryExpressionArguments<T1, T2>(AstBinaryExpression binaryExpression, out T1 arg1, out T2 arg2)
Copy link
Member Author

Choose a reason for hiding this comment

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

Theoretically could be reusable.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can wait until there is a need.

@sanych-sun sanych-sun removed the request for review from a team January 4, 2025 01:31
@@ -103,6 +103,50 @@ static bool OperatorMapsNullToNull(AstUnaryOperator @operator)
}
}

public override AstNode VisitExprFilter(AstExprFilter node)
{
var optimizedNode = (AstExprFilter)base.VisitExprFilter(node);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it safe to assume base.VisitExprFilter always returns an AstExprFilter? I guess looking at the source code we can convince ourselves that it does.

fieldPathExpression.Path.Length > 1 && fieldPathExpression.Path[0] == '$' && fieldPathExpression.Path[1] != '$' &&
varExpression == mapExpression.As)
{
return AstFilter.In(AstFilter.Field(fieldPathExpression.Path.Substring(1)), inputArrayValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a comment just before this line to visualize the simplification being done:

// { $expr : { $anyElementTrue : { $map : { input : <constantArray>, as : "<var>", in : { $eq : ["$<dottedFieldName>", "$$<var>"] } } } } }
//      => { "<dottedFieldName>" : { $in : <constantArray> } }                   
return AstFilter.In(AstFilter.Field(fieldPathExpression.Path.Substring(1)), inputArrayValue);                                                         

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

mapExpression.In is AstBinaryExpression inBinaryExpression &&
inBinaryExpression.Operator == AstBinaryOperator.Eq &&
TryGetBinaryExpressionArguments(inBinaryExpression, out AstFieldPathExpression fieldPathExpression, out AstVarExpression varExpression) &&
fieldPathExpression.Path.Length > 1 && fieldPathExpression.Path[0] == '$' && fieldPathExpression.Path[1] != '$' &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what you mean.

But anything that starts with $$ is not a field so I think that's all we need to check.


return optimizedNode;

static bool TryGetBinaryExpressionArguments<T1, T2>(AstBinaryExpression binaryExpression, out T1 arg1, out T2 arg2)
Copy link
Contributor

Choose a reason for hiding this comment

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

We can wait until there is a need.


namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira
{
public class AnyEqualTests : Linq3IntegrationTest
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the file name we want for these tests?

Oleksandr Poliakov added 2 commits January 6, 2025 13:47
@sanych-sun sanych-sun requested a review from rstam January 7, 2025 02:43
Copy link
Contributor

@rstam rstam left a comment

Choose a reason for hiding this comment

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

Nice work! LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants