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

Query: Adds ArrayContains to CosmosLinqExtensions to allow partial matching on array fields in queries #4992

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

bcrobinson
Copy link

@bcrobinson bcrobinson commented Jan 31, 2025

Pull Request Template

Description

The Array_Contains function CosmosDB Sql has a 3rd parameter which allows it to do a partial match on the given item. This is unable to be called with the built in Linq array.Contains(item) extension methods.

This adds this adds an explicit mapping to this function to allow it to be called in Linq like this:

documents.Where(document => document.ObjectArray.ArrayContains(new { Name = "abc" }, true))

Remarks

New extension method called ArrayContains instead of Contains

I namef the new CosmosLinqExtensions extension method ArrayContains instead of Contains as the other extensions methods matched thier Cosmos Sql counterparts and because this is for a direct invokation of this function.

Can change the name if you require.

ArrayContains Signature
bool ArrayContains(this IEnumerable obj, object itemToMatch, bool partialMatch)

The itemToMatch paramater is an object as it will need to take anonymous objects (and c# doesn't have a similar concept to typescript's Partial<T>). If was generic callers would be force to pass in an object of the same type, and the default serialiser creates object with every property that exists on the class. So the created query object with default values (e.g. Array_Contains(root["Items"], { "I" = 0, "s" = null }) )which would the cause Cosmos to try and match on all properties.

Because it's not generic the obj is then IEnumerable, so it would at a minimum only work on iterable values.

bool ArrayContains(this IEnumerable obj, object itemToMatch, bool partialMatch)

If this was ArrayContains<T>(this IEnumerable<T> obj, T itemToMatch, bool partialMatch) then we'd need to always pass the same T type to this method, and the serialiser would then serialise all the properties on the type T, which would cause the partial matching in cosmos to fail. The downside is you loose some type checking (the anonymous object could have a property name typed wrong),

Modification to ArrayContainsVisitor

The ArrayContainsVisitor visitor already exists for the Contains Linq mappings, the I modified this to work with the different extension version for Array Contains.

Type of change

  • New feature (non-breaking change which adds functionality)

Closing issues

closes #4991

To automatically close an issue: closes #IssueNumber

@bcrobinson bcrobinson force-pushed the feature/array_contains_builtin_function branch from 3c89ee6 to e7785f8 Compare January 31, 2025 16:01
@bcrobinson
Copy link
Author

@microsoft-github-policy-service agree company="Solarvista Software LTD"

@bcrobinson bcrobinson force-pushed the feature/array_contains_builtin_function branch 2 times, most recently from 8ec125f to f6b6d84 Compare February 3, 2025 15:17
The `Array_Contains` funtion CosmosDB Sql has a 3rd parameter which allows it to do a partial match on the given item. This is unable to be called with the built in Linq `array.Contains(item)` extension methods.

This adds this adds an explicit mapping to this function to allow it to be called in Linq like this:
`documents.Where(document => document.ObjectArray.ArrayContains(new { Name = "abc" }, true))`
@bcrobinson bcrobinson force-pushed the feature/array_contains_builtin_function branch from f6b6d84 to 786db81 Compare February 3, 2025 15:55
@bcrobinson bcrobinson marked this pull request as ready for review February 5, 2025 14:46
@bcrobinson bcrobinson changed the title Added ArrayContains to CosmosLinqExtensions to allow partial matching Query: Adds ArrayContains to CosmosLinqExtensions to allow partial matching on array fields in queries Feb 5, 2025
@adityasa
Copy link
Contributor

adityasa commented Feb 5, 2025

@bcrobinson technically adding this functionality makes sense. However, ARRAY_CONTAINS with partial match is a very expensive function (both RU consumption and latency wise) and use of it is generally discouraged in favor of another pattern.

new LinqTestInput("ArrayContains in Select clause with int value and match partial false", b => getQuery(b).Select(doc => doc.ArrayField.ArrayContains(1, false))),
new LinqTestInput("ArrayContains in Filter clause with int value and match partial false", b => getQuery(b).Where(doc => doc.ArrayField.ArrayContains(1, false))),
new LinqTestInput("ArrayContains in Select clause with object value and match partial false", b => getQuery(b).Select(doc => doc.ObjectArrayField.ArrayContains(new { Field = "abc" }, false))),
new LinqTestInput("ArrayContains in Filter clause with object value and match partial false", b => getQuery(b).Where(doc => doc.ObjectArrayField.ArrayContains(new { Field = "abc" }, false))),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also include coverage for ArrayContains without third parameter?

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.

Add Array_Contains partial match support to Linq
2 participants