[CSHARP-1487] Linq: bad $elemMatch for discriminator of array field Created: 23/Nov/15  Updated: 07/Apr/23  Resolved: 11/Mar/16

Status: Closed
Project: C# Driver
Component/s: Linq
Affects Version/s: 2.1.1
Fix Version/s: 2.2.4

Type: Bug Priority: Major - P3
Reporter: Federico Ceccatto Assignee: Craig Wilson
Resolution: Done Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

x64 Windows 7 & Windows Server 2012 R2; possibly other Win versions.


Backwards Compatibility: Major Change

 Description   

Hello,
After upgrading to 2.1.1, we've noticed a problem with one of the oldest LINQ queries in our system which no longer filtered down a set of results to what we needed but instead returned just about every document in the collection.

After tinkering with the underlying issue for a bit, here's a short, self-contained example:

namespace CodePad
{
    using System;
    using System.Linq;
    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    using MongoDB.Driver;
 
    [BsonKnownTypes(typeof(A), typeof(B), typeof(AA))]
    [BsonDiscriminator(RootClass = true)]
    public abstract class Base
    {
        public int[] Values { get; set; }
        public Thing[] Things { get; set; }
    }
 
    public class A : Base
    {
    }
 
    public class AA : A
    {
    }
 
    public class B : Base
    {
    }
 
    public class Container
    {
        public ObjectId Id { get; set; }
        public Base[] Records { get; set; }
    }
 
    public class Thing
    {
        public int Value { get; set; }
    }
 
    internal class Program
    {
        static void Main(string[] args)
        {
            var coll = new MongoClient().GetDatabase("Example").GetCollection<Container>("Containers");
 
            coll.DeleteManyAsync(Builders<Container>.Filter.Empty).Wait();
            coll.InsertOneAsync(new Container{Records = new Base[]{new AA()}}).Wait();
 
            var queryBad = coll.AsQueryable().Where(_ => _.Records.Any(r => r is A));
            var queryGood1 = coll.AsQueryable().Where(_ => _.Records.Any(r => r.Values.Any(v => v > 3 && v < 56)));
            var queryGood2 = coll.AsQueryable().Where(_ => _.Records.Any(r => r.Things.Any(t => t.Value > 3 && t.Value < 56)));
            var queryGood3 = coll.AsQueryable().Where(_ => _.Records.Any(r => r.GetType() == typeof (A)));
 
            Console.WriteLine(queryBad);
            Console.WriteLine(queryGood1);
            Console.WriteLine(queryGood2);
            Console.WriteLine(queryGood3);
            Console.ReadKey(true);
        }
    }
}

The above code results in the following output:

aggregate([{ "$match" : { "Records" : { "$elemMatch" : { "._t" : "A" } } } }])
aggregate([{ "$match" : { "Records.Values" : { "$elemMatch" : { "$gt" : 3, "$lt" : 56 } } } }])
aggregate([{ "$match" : { "Records.Things" : { "$elemMatch" : { "Value" : { "$gt" : 3, "$lt" : 56 } } } } }])
aggregate([{ "$match" : { "Records._t" : { "$size" : 2 }, "Records._t.0" : "Base", "Records._t.1" : "A" } }])

The first query adds a spurious "." before "_t" which basically matches to nothing. I've attempted to trigger the same bug with other fields (array of primitive BSON numbers, array of objects, another query over the discriminator using GetType()) but I couldn't get it to manifest except for the "is" keyword.

Please let me know if you need any more information.
Thanks for your time!



 Comments   
Comment by Githook User [ 11/Mar/16 ]

Author:

{u'username': u'craiggwilson', u'name': u'Craig Wilson', u'email': u'craiggwilson@gmail.com'}

Message: CSHARP-1487: fixed issue with the type is operator used on the variable in an Any method.
Branch: v2.2.x
https://github.com/mongodb/mongo-csharp-driver/commit/f8546d5fe2924e97d822655d365aeaac7b611d53

Comment by Githook User [ 11/Mar/16 ]

Author:

{u'username': u'craiggwilson', u'name': u'Craig Wilson', u'email': u'craiggwilson@gmail.com'}

Message: CSHARP-1487: fixed issue with the type is operator used on the variable in an Any method.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/268c8f3e63ba0bd46dfb621b8d4f89be87e919f9

Comment by Craig Wilson [ 27/Jan/16 ]

Hi Frederico,

I've reproduced this. Thanks for the report. We'll queue this up for fixing.

Craig

Comment by Federico Ceccatto [ 09/Dec/15 ]

Hi Craig,
Apologies for the late reply: we upgraded from the old 1.x driver line, so the generated queries were not aggregations at all to begin with.

The "._t" fragment seems to be constructed in line 1519 of Linq/Translators/PredicateTranslator.cs, due to a 'true' return value from ExpressionHelper.TryGetExpression, but I cannot say whether the problem lies in the helper or directly in TranslateTypeIsQuery().

Comment by Craig Wilson [ 04/Dec/15 ]

Hi Federico,

You said after upgrading to 2.1.1. What version did you upgrade from? Also, prior to upgrading, which of these queries were you running and what was the query that was generated?

Craig

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