Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-5031

AnyEq (object item) + Size merges the passed object and the size query into a single object

    • Type: Icon: Bug Bug
    • Resolution: Unresolved
    • Priority: Icon: Unknown 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. 

       

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            john.fricker@splyza.com John Fricker
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: