[CSHARP-1668] Allow FilterDefinition OfType to allow for querying of inherited types with type safety in builder Created: 12/May/16  Updated: 05/Apr/19  Resolved: 03/Nov/17

Status: Closed
Project: C# Driver
Component/s: Read Operations
Affects Version/s: 2.2.3
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: Chad Kreimendahl Assignee: Robert Stam
Resolution: Done Votes: 2
Labels: question
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to CSHARP-1635 Create a filter builder method generi... Closed

 Description   

The ability to use builders for typesafety with expressions is excellent, especially given our abundant use of the BsonClassMap to map field names, and occasionally change them.

We would like the ability to do the following:

Builders<RootType>.Filter.OfType<SubType>().ElemMatch(c => c.SomeThing, Builders<SubType>.Filter.Eq(c => c.SubTypeBoolean, true))



 Comments   
Comment by Robert Stam [ 03/Nov/17 ]

Suppose you had a collection of documents of type Root, with subclasses S and T.

public class Root
{
    public int Id { get; set; }
    public int RV { get; set; }
}
 
public class S : Root
{
    public int SV { get; set; }
}
 
public class T : Root
{
    public int TV { get; set; }
}

If I'm understanding correctly what you want to do, you want a single query that checks some properties only available in some subclasses.

Let's assume you want to return all documents that match any of the following:

1. All documents where TV == 1
2. All documents of subtype S where SV == 2
3. All documents of subtype T where TV == 3

This can be written as follows:

var builder = Builders<Root>.Filter;
var filter = builder.Or(
    builder.Where(r => r.RV == 1),
    builder.OfType<S>(s => s.SV == 2),
    builder.OfType<T>(t => t.TV == 3));
var cursor = collection.FindSync(filter);

which results in the following query being sent to the server:

{ "$or" : [
    { "RV" : 1 }, 
    { "_t" : "S", "SV" : 2 }, 
    { "_t" : "T", "TV" : 3 }
] }

Comment by Chad Kreimendahl [ 25/Aug/16 ]

Our main issue is that second comment I posted. Though an .Or() would likely be more appropriate given how I showed the two Eqs. Basically we frequently need to pull back a bunch of records where some overall setting is there, or some subtype setting also exists.

Comment by Craig Wilson [ 10/Aug/16 ]

Chad,

I was about to start adding these and we already have OfType on FilterDefintions. See here: https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/FilterDefinitionBuilder.cs#L966-L1054.

Is there something missing that doesn't satisfy your needs. We can't fix the covariance problem as that is a compiler thing.

Craig

Comment by Chad Kreimendahl [ 27/May/16 ]

Another good example of this would be

Builders<RootType>.And(
  Builders<RootSubTypeOne>.Eq(c => c.ValueOnlyInFirstClass, value) |
  Builders<RootSubTypeTwo>.Eq(c => c.ValueOnlyInSecondClass, value2));

Comment by Chad Kreimendahl [ 19/May/16 ]

It would be really interesting if you could somehow get the following done. I'm having a painful time wrapping my head around how this would be written to work in the driver, as there doesn't seem to be a way in C# to accept covariants of generics:

class SubType : RootType { private bool SubTypeOnlyBool {get;set;} }
...
 
var collection = Database.GetCollection<RootType>("roots");
var filter = Builders<SubType>.Filter.Eq(c => c.SubTypeOnlyBool, true);
collection.Find(filter);

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