Reputation: 340
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
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