[CSHARP-2963] And filter with $near translates to invalid MongoDb query Created: 11/Feb/20  Updated: 28/Oct/23  Resolved: 24/Apr/20

Status: Closed
Project: C# Driver
Component/s: Builders
Affects Version/s: 2.10.1
Fix Version/s: 2.11.0

Type: Bug Priority: Major - P3
Reporter: daniel moqvist Assignee: Dmitry Lukyanov (Inactive)
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows


Attachments: PNG File map.png    
Issue Links:
Related

 Description   

If we create multiple geo conditions on the same field in one query, and one condition is the near operator. The driver don't translate this to a correct MongoDb query. The following code demonstrate the behaviour. And the result and exception message is as comments.

using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using MongoDB.Driver.GeoJsonObjectModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace MongoDbJira
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new MongoClient("mongodb://localhost");
            var database = client.GetDatabase("testdb");
            database.DropCollection("test");
            var collection = database.GetCollection<BsonDocument>("test");
            var indexModel = new CreateIndexModel<BsonDocument>(new IndexKeysDefinitionBuilder<BsonDocument>().Geo2DSphere("geoField"));
            collection.Indexes.CreateOne(indexModel);            collection.InsertOne(BsonDocument.Parse("{'geoField':{'type':'Point','coordinates':[18.07309566753327, 59.31119815301082]}, 'name':'A'}"));
            collection.InsertOne(BsonDocument.Parse("{'geoField':{'type':'Point','coordinates':[18.031779179282793 59.31869226401174]} 'name':'B'}"));
            
            var filterDefinitions = new List<FilterDefinition<BsonDocument>>();
            filterDefinitions.Add(Builders<BsonDocument>.Filter.GeoWithinBox("geoField", 18.02768052426505, 59.302264601734144, 18.103211530124426, 59.32407863571196));
            filterDefinitions.Add(Builders<BsonDocument>.Filter.Near("geoField", new GeoJsonPoint<GeoJson2DCoordinates>(new GeoJson2DCoordinates(18.07176, 59.31395)), 500));
            var filterDefinition = Builders<BsonDocument>.Filter.And(filterDefinitions);
            var failingFilterDefinitionAsString = filterDefinition.Render(BsonSerializer.SerializerRegistry.GetSerializer<BsonDocument>(), BsonSerializer.SerializerRegistry).ToString();
            Console.WriteLine(failingFilterDefinitionAsString); //{ "geoField" : { "$geoWithin" : { "$box" : [[18.027680524265051, 59.302264601734144], [18.103211530124426, 59.324078635711963]] }, "$near" : { "$geometry" : { "type" : "Point", "coordinates" : [18.071760000000001, 59.313949999999998] }, "$maxDistance" : 500.0 } } }            try
            {
                var failingFindResult = collection.Find(filterDefinition).ToList();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message); //Command find failed: can't parse extra field: $near: { $geometry: { type: "Point", coordinates: [ 18.07307303636145, 59.31128165641481 ] }, $maxDistance: 500.0 }.
            }
            var myFilterBuilder = new StringBuilder();
            myFilterBuilder.Append("{$and:[");
            for (int i = 0; i < filterDefinitions.Count; i++)
            {
                if (i > 0)
                {
                    myFilterBuilder.Append(",");
                }
                myFilterBuilder.Append(filterDefinitions.ElementAt(i).Render(BsonSerializer.SerializerRegistry.GetSerializer<BsonDocument>(), BsonSerializer.SerializerRegistry).ToString());
            }
            myFilterBuilder.Append("]}");
            var successfulFilterDefintionAsString = BsonSerializer.Deserialize<BsonDocument>(myFilterBuilder.ToString());
            Console.WriteLine(successfulFilterDefintionAsString); //{{ "$and" : [{ "geoField" : { "$geoWithin" : { "$box" : [[18.027680524265051, 59.302264601734144], [18.103211530124426, 59.324078635711963]] } } }, { "geoField" : { "$near" : { "$geometry" : { "type" : "Point", "coordinates" : [18.071760000000001, 59.313949999999998] }, "$maxDistance" : 500.0 } } }] }}            var successfulFindResult = collection.Find(successfulFilterDefintionAsString).ToList();
            Console.WriteLine(successfulFindResult[0]["name"]); //A            Console.ReadKey();
        }
    }
}

The attached image describe the geometry objects used in this example.



 Comments   
Comment by Githook User [ 24/Apr/20 ]

Author:

{'name': 'DmitryLukyanov', 'email': 'dmitry.lukyanov@mongodb.com', 'username': 'DmitryLukyanov'}

Message: CSHARP-2963: And filter with $near translates to invalid MongoDb query.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/910e9da8629e34239ca5ece1069f209d4e753df8

Comment by daniel moqvist [ 11/Feb/20 ]

The code include a stringbuilder that create a correct formatted MongoDb query that can execute and get the desired result.

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