[CSHARP-4491] Filtering joined collections only works with inline predicates Created: 24/Jan/23  Updated: 21/Apr/23

Status: Backlog
Project: C# Driver
Component/s: LINQ3
Affects Version/s: 2.18.0
Fix Version/s: None

Type: New Feature Priority: Minor - P4
Reporter: Alexandre Junior Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Summary

Filtering joined collections only works with inline predicates/lamba expressions.

Example

This works:

 

await _personCollection.AsQueryable()
      .GroupJoin(_carCollection.AsQueryable(), r => r.PersonId, a => a.PersonId, (p, c) => new { person = p, cars = c.Where(t => t.IsActive == true).DefaultIfEmpty() })
      .Select(t => new PersonReportDto
      {
         PersonName = person.Name,
         Cars = cars
      })
      .ToListAsync();

 

 

Notice the inline t => t.IsActive == true


This doesn't work:

var carFilterDefinition = Builders<Car>.Filter.Where(/* my custom predicate (Expression<Func<>>), received by parameter */); 
 
await _personCollection.AsQueryable()
  .GroupJoin(_carCollection.AsQueryable(), r => r.PersonId, a => a.PersonId, (p, c) => new { person = p, cars = c.Where(_ => carFilterDefinition.Inject()).DefaultIfEmpty() })
    .Select(t => new PersonReportDto
    {
       PersonName = person.Name,
       Cars = cars
    })
.ToListAsync();
 
// Runtime error: Expression not supported: Inject()

Also is worth mentioning that passing an Expression<Func<TDocument, bool>> parameter directly to the Where }}is not possible due to {{cars collection being of type IEnumerable<Car> and not IQueryable<Car>



 Comments   
Comment by James Kovacs [ 13/Feb/23 ]

We have added this feature request to our backlog and will consider it for a future version. We will happily consider pull requests. You can see our brief Contributing guide. You can add a test file:

tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/Jira/CSharp4491Tests.cs

and then implement support for the Inject method within MethodCallExpressionToAggregationExpressionTranslator.

Comment by Alexandre Junior [ 30/Jan/23 ]

Thanks for the response.

Since the bits and bolts to do the filtering are already in place (inline filtering works), it's just a matter (I think) of parsing the Inject() function to apply the FilterDefinition to the pipeline.

Comment by James Kovacs [ 28/Jan/23 ]

Repro run against 2.19.0:

using System.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
 
var client = new MongoClient();
var db = client.GetDatabase("test");
var _personCollection = db.GetCollection<Person>("people");
var _carCollection = db.GetCollection<Car>("cars");
 
var carFilterDefinition = Builders<Car>.Filter.Where(x => x.Type == "fast");
 
var results = await _personCollection.AsQueryable()
    .GroupJoin(_carCollection.AsQueryable(), r => r.PersonId, a => a.PersonId, (p, c) => new { person = p, cars = c.Where(x => carFilterDefinition.Inject()).DefaultIfEmpty() })
    .Select(t => new
    {
        PersonName = t.person.Name,
        Cars = t.cars
    })
    .ToListAsync();
 
public class Car
{
    public int PersonId { get; set; }
    public string Type { get; set; }
}
 
public class Person
{
    public int PersonId { get; set; }
    public string Name { get; set; }
}

Failure with stack trace:

Unhandled exception. MongoDB.Driver.Linq.ExpressionNotSupportedException: Expression not supported: value(MongoDB.Driver.ExpressionFilterDefinition`1[Car]).Inject().
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodCallExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs:line 173
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 61
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators.WhereMethodToAggregationExpressionTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WhereMethodToAggregationExpressionTranslator.cs:line 41
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodCallExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs:line 77
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 61
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.TranslateEnumerable(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 83
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators.DefaultIfEmptyMethodToAggregationExpressionTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs:line 35
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodCallExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs:line 40
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 61
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.NewExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, NewExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewExpressionToAggregationExpressionTranslator.cs:line 67
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.Translate(TranslationContext context, Expression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs:line 71
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.GroupJoinMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression) in /Users/james/Dropbox/code/mongodb/mongo-csharp-driver/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/GroupJoinMethodToPipelineTranslator.cs:line 72

Comment by James Kovacs [ 28/Jan/23 ]

Thank you for reporting this issue. Inject() is currently supported in top-level Where clauses in LINQ3 (see CSHARP-3979), but not in nested Where clauses as in your example. We will investigate supporting this in a future version.

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