[CSHARP-3144] Linq Contains produce wrong expression Created: 25/Jun/20  Updated: 28/Oct/23  Resolved: 29/Oct/22

Status: Closed
Project: C# Driver
Component/s: Linq
Affects Version/s: 2.10.4
Fix Version/s: 2.19.0

Type: New Feature Priority: Major - P3
Reporter: Анатолий Крыжановский Assignee: Robert Stam
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

.net core 3.1


Backwards Compatibility: Fully Compatible

 Description   

when i try to check if collection contains some element i get System.ArgumentException: Unsupported filter: Contains().

for example, we have Order class with collection of order positions:

class Order

{    public int Id \{ get; set; }

   public List<OrderItem> Items { get; set; }

...

}

 

in each position we have GoodId and Amount:

class OrderPosition
{    public int Id { get; set; }

   public int GoodId { get; set; }

   public int Amount { get; set; }

}

 

now i want to select all Orders where some  good is present:

var orders = db
   .GetCollection<Order>("order").AsQueryable()
   .Where(x => x.Items.Select(e => e.GoodId).Contains(2))
   .ToArray();

 

yes, i know that i can rewrite query, but thissample is adopted my work case, so i nee dexactly that expression

 

and there is i get exception:

System.ArgumentException: Unsupported filter: Contains({document}

{Items}

.Select({document}

{GoodId}

)).
at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node)
at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslateWhere(WhereExpression node)
at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node)
at MongoDB.Driver.Linq.Translators.QueryableTranslator.TranslatePipeline(PipelineExpression node)
at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node)
at MongoDB.Driver.Linq.Translators.QueryableTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Translate(Expression expression)
at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Execute(Expression expression)
at MongoDB.Driver.Linq.MongoQueryableImpl`2.GetEnumerator()
at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at ConsoleApp1.Program.Main(String[] args) in 

 

now i use workaround and use following expression:

var orders = db
   .GetCollection<Order>("order").AsQueryable()
   .Where(x => x.Items.Select(e => e.GoodId).Any(e => e == 2))
   .ToArray();

 

but iu think that this bug need to be fixed

 

i created fiddle with full example: https://dotnetfiddle.net/yfQk7U



 Comments   
Comment by Githook User [ 29/Oct/22 ]

Author:

{'name': 'rstam', 'email': 'robert@robertstam.org', 'username': 'rstam'}

Message: CSHARP-3144: Linq Contains produce wrong expression.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/9613bb44de65df516e54e32212148fb6a3f39188

Comment by Robert Stam [ 18/Oct/22 ]

My repro confirming that this works in LINQ3 is in code review on this branch:

https://github.com/rstam/mongo-csharp-driver/tree/csharp3144

The original query:

.Where(x => x.Items.Select(e => e.GoodId).Contains(2))

translates to:

{ $match : { $expr : { $in : [2, '$Items.GoodId'] } } }

and the suggested workaround:

.Where(x => x.Items.Select(e => e.GoodId).Any(e => e == 2))

translates to:

{ $match : { $expr : { $anyElementTrue : { $map : { input : '$Items.GoodId', as : 'e', in : { $eq : ['$$e', 2] } } } } } }

Comment by Robert Stam [ 18/Oct/22 ]

This issue has been fixed in the new LINQ provider (known as LINQ3), which was introduced in the 2.14 release.

Configure your MongoClientSettings to use LinqProvider.V3 if you want to use this functionality.

To configure a client to use the LINQ3 provider use code like the following

var connectionString = "mongodb://localhost";
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
clientSettings.LinqProvider = LinqProvider.V3;
var client = new MongoClient(clientSettings);

Comment by Анатолий Крыжановский [ 25/Jun/20 ]

additional info: expression from workaround does not work also

Generated at Wed Feb 07 21:44:30 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.