1

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

5
  • Since products is an array field, I think you need to use an aggregation operators to match the array elements using regex. Commented Apr 23, 2021 at 11:59
  • Thanks @prasad, that makes allot of sense. Will take a look at the link you shared. Commented Apr 23, 2021 at 12:31
  • Essentially this is what I am looking to code in C#. db.getCollection('users').aggregate([{ $match : { "product" : { "$exists" : true } , "product.name" : "A product name" } }]) Commented Apr 23, 2021 at 13:06
  • Here are posts with similar issue: Filter array elements with $regex and Regex inside array in mongoDB Commented Apr 23, 2021 at 13:11
  • 1
    Thanks again @prasad , final step for me is to workout how to use the C# driver syntax to do this programatically.. Commented Apr 23, 2021 at 15:00

1 Answer 1

1

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/
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.