yogibear
yogibear

Reputation: 340

C# Mongo Builders<T>.Filter lambda for an array field

How do I use lambda expressions in C# with Builders and lambda expressions to match against a field in an array of a class. Let me clarify.

Presently I have a document in mongo, and a C# class. I am using aggregation pipeline to match documents. I do this using a lambda expression for type safety and elegance reasons.

I have the follow code to add a filter.

    public RegularExpressionFilterSingle<T> AddFilter(
        Expression<Func<T, object>> FilterSpecification)
    {
        FilterDefinitions.Add(
            Builders<T>.Filter.
                Regex(
                    FilterSpecification, // e.g. x => x.Email
                    new BsonRegularExpression(Text,"i")));

        return this;
    }

The the following code will add a number of filters.

                RegularExpressionFilterSingle<User>
                RegExp = new RegularExpressionFilterSingle<User>
                    (new List<FilterDefinition<User>>(), Word.Trim()).
                        AddFilter(x => x.Email).
                        AddFilter(x => x.Title).
                        AddFilter(x => x.FirstName).
                        AddFilter(x => x.LastName);

This all works nicely the document structure at this stage is flat only fields. Now I have added a field which is list of a class, in C# this is.

    [BsonElement("product")]
    public List<UserProduct> Products { get; set; } = default;

So I want to add a filter which also matches against items in this array. My partially working attempt is as follows.

                RegularExpressionFilterSingle<User>
                RegExp = new RegularExpressionFilterSingle<User>
                    (new List<FilterDefinition<User>>(), Word.Trim()).
                        AddFilter(x => x.Email).
                        AddFilter(x => x.Title).
                        AddFilter(x => x.FirstName).
                        AddFilter(x => x.LastName).
                        AddFilter(x => x.Products[1].Name); 

You will notice the addition of

AddFilter(x => x.Products[1].Name); 

How do I search so that if any of the Products[...].Name matches not just the one at index 1?

I did come across this post (Lambda Expression to filter a list of list of items), but it didn't seem to answer my questions.

Many thanks

Upvotes: 1

Views: 1037

Answers (1)

Dĵ ΝιΓΞΗΛψΚ
Dĵ ΝιΓΞΗΛψΚ

Reputation: 5669

the mongo driver can't translate the member expression you need for the regex filter to work in a strongly-typed manner.

you'd have to create your own function that will take in a lambda and convert it to a dotted string path.

i've already created such a function for my mongodb library which you can find here

with it you can simply do the following:

var filter = Builders<User>.Filter
    .Regex(Prop.Path<User>(u => u.Products[0].Name),
        "^something");

which will translate to the following filter if you do an aggregate query with it:

{
    "$match" : {
        "Products.Name" : /^something/
    }
}

Upvotes: 1

Related Questions