-
Type: Bug
-
Resolution: Unresolved
-
Priority: Unknown
-
None
-
Affects Version/s: 2.17.0, 2.22.0, 2.24.0
-
Component/s: None
-
Labels:None
-
Dotnet Drivers
Summary
When querying a list of objects in a document using AnyEq and then combining that with a Size query on the same list, the driver is combining the passed object with the size operator.
Expected query:
{ $and: [ { "Items" : { "Value" : "Hello" } }, { "Items": { "$size" : 1 } } ] }
Generated query:
{ "Items" : { "Value" : "Hello", "$size" : 1 } }
When comparing an object, the second query obviously can't match. Note that my actual object is a little more complex as it includes a type property and a value property, but for the sake of this repro, an extra field isn't needed.
It seems that this only affects AnyEq when querying with objects as, if I change the list of object to list of string, the generate query makes a lot more sense and actually matches the documents correctly:
{ "$and" : [{ "Items" : "Hello" }, { "Items" : { "$size" : 1 } }] }
Please provide the version of the driver. If applicable, please provide the MongoDB server version and topology (standalone, replica set, or sharded cluster).
I have tried with driver versions 2.17.0, 2.22.0, 2.24.0, and 2.32.0 (pre-release) and the same behaviour is exhibited with all.
Locally I'm testing with the Mongo:5.0 Docker image, and in our Sandbox environment, we're running against a M10 5.0.26 Atlas cluster (3-node replica set). The same behaviour (no results returned) can be seen both locally and against the Atlas-hosted cluster.
How to Reproduce
Test models:
public class MyDocument { public ObjectId Id { get; set; } public IList<MyArrayItem> Items { get; set; } //public IList<string> Items { get; set; } } public class MyArrayItem { public string Value { get; set; } }
Test code:
var mongoSettings = new MongoClientSettings() { Server = new MongoServerAddress("localhost", 3000), ClusterConfigurator = builder => { builder.Subscribe<CommandStartedEvent>(e => Console.WriteLine(e.Command)); } }; var mongoClient = new MongoClient(mongoSettings); var mongoDatabase = mongoClient.GetDatabase("size-bug-sample"); const string collectionName = "sample-20240411"; await mongoDatabase.DropCollectionAsync(collectionName); var mongoCollection = mongoDatabase.GetCollection<MyDocument>(collectionName);var sampleDoc = new MyDocument() { Items = new List<MyArrayItem>() { new MyArrayItem() { Value = "Hello" } } }; //var sampleDoc = new MyDocument() { Items = new List<string>() { "Hello" } }; await mongoCollection.InsertOneAsync(sampleDoc); Console.WriteLine("> AnyEq & Size"); var singleItemDocs = await mongoCollection .Find( Builders<MyDocument>.Filter.AnyEq(d => d.Items, sampleDoc.Items.First()) & Builders<MyDocument>.Filter.Size(d => d.Items, 1) ) .ToListAsync(); Console.WriteLine(); Console.WriteLine("Matched {0} documents.", singleItemDocs.Count); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("> $and: [ AnyEq, Size ]"); var singleItemDocs_FilterAnd = await mongoCollection .Find( Builders<MyDocument>.Filter.And( Builders<MyDocument>.Filter.AnyEq(d => d.Items, sampleDoc.Items.First()), Builders<MyDocument>.Filter.Size(d => d.Items, 1) ) ) .ToListAsync(); Console.WriteLine(); Console.WriteLine("Matched {0} documents.", singleItemDocs_FilterAnd.Count); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("> AnyEq"); var singleItemDocs_AnyEqOnly = await mongoCollection .Find( Builders<MyDocument>.Filter.AnyEq(d => d.Items, sampleDoc.Items.First()) ) .ToListAsync(); Console.WriteLine(); Console.WriteLine("Matched {0} documents.", singleItemDocs_AnyEqOnly.Count); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("> Size"); var singleItemDocs_SizeOnly = await mongoCollection .Find( Builders<MyDocument>.Filter.Size(d => d.Items, 1) ) .ToListAsync(); Console.WriteLine(); Console.WriteLine("Matched {0} documents.", singleItemDocs_SizeOnly.Count);
You can swap between the list of documents and list of strings to see the difference between the behaviour in both cases. In both cases, I would expect "Matched {0} documents." to print "Matched 1 documents." in every case, but when querying by objects, only the last two queries (where I'm not querying with AnyEq AND Size in the same query) return documents.
Additional Background
The output when running the code above is like this:
> AnyEq & Size { "find" : "sample-20240411", "filter" : { "Items" : { "Value" : "Hello", "$size" : 1 } }, "$db" : "size-bug-sample", "lsid" : { "id" : CSUUID("9e162409-07f3-46bc-a625-d4dfacd33ff2") } } Matched 0 documents. > $and: [ AnyEq, Size ] { "find" : "sample-20240411", "filter" : { "Items" : { "Value" : "Hello", "$size" : 1 } }, "$db" : "size-bug-sample", "lsid" : { "id" : CSUUID("9e162409-07f3-46bc-a625-d4dfacd33ff2") } } Matched 0 documents. > AnyEq { "find" : "sample-20240411", "filter" : { "Items" : { "Value" : "Hello" } }, "$db" : "size-bug-sample", "lsid" : { "id" : CSUUID("9e162409-07f3-46bc-a625-d4dfacd33ff2") } } Matched 1 documents. > Size { "find" : "sample-20240411", "filter" : { "Items" : { "$size" : 1 } }, "$db" : "size-bug-sample", "lsid" : { "id" : CSUUID("9e162409-07f3-46bc-a625-d4dfacd33ff2") } } Matched 1 documents.