-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: None
-
None
Summary
With the latest C# driver (2.15.1), when running an aggregate query that includes a projection step with a LINQ predicate, the predicate is compiled ignoring any of the custom serializers, resulting in an incorrect query.
Visual Studio 2019
.NET Core 3.1
MongoDB.Driver 2.15.1
How to Reproduce
Consider the following program:
class Program { static void Main(string[] args) { var mongo = new MongoClient(new MongoUrl("mongodb://localhost:27017/local")); var database = mongo.GetDatabase("local"); var findQuery = database.GetCollection<Order>("orders") .Find(o => o.Items.Any(i => i.Type == ItemType.Refund)); Console.WriteLine(findQuery.ToString()); var query = database.GetCollection<Order>("orders") .Aggregate() .Project((o) => new { o.Id, HasAnyRefund = o.Items.Any(i => i.Type == ItemType.Refund) }); Console.WriteLine(query.ToString()); } } public class Order { public int Id { get; set; } public List<Item> Items { get; set; } } public class Item { [BsonSerializer(typeof(CamelCaseEnumSerializer<ItemType>))] public ItemType Type { get; set; } } public enum ItemType { SaleItem, Refund } public class CamelCaseEnumSerializer<T> : EnumSerializer<T> where T : struct, Enum { private static string ToCamelCase(string s) { return char.ToLowerInvariant(s[0]) + s.Substring(1); } public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) { context.Writer.WriteString(ToCamelCase(value.ToString())); } public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { return (T)Enum.Parse(typeof(T), context.Reader.ReadString(), true); } }
In the above example, a custom serializer is registered for the Enum type, which should be respected. When the standard Find query is run, the output is:
find({ "Items" : { "$elemMatch" : { "Type" : "refund" } } })
however, when the Aggregate query is run, the output is:
aggregate([{ "$project" : { "Id" : "$_id", "HasAnyRefund" : { "$anyElementTrue" : { "$map" : { "input" : "$Items", "as" : "i", "in" : { "$eq" : ["$$i.Type", 1] } } } }, "_id" : 0 } }])
Clearly, the predicate in the projection is not being compiled with serializers and it's serializing ItemType.Refund as 1 (its Enum index) instead of "refund" (as per the serializer).
- is duplicated by
-
CDRIVER-4388 Aggregate projection with LINQ expression ignores serializers
- Closed