Search code examples
c#mongodb.net-coremongodb-.net-drivermongodb-geospatial

Filtering several Geo near operations in a query sends an error


I made a filter to do a Geospatial query on data from my Mongodb database and this filter works fine until I do an "And" operation on this filter with another Geospatial filter, but pointing to a different Property on the Collection I'm querying. When I add this filter, I get an Exception stating:

Message: MongoDB.Driver.MongoCommandException : Command find failed: Too many geoNear expressions.

Here is the first filter,


                var point = GeoJson.Point(GeoJson.Geographic(longitude: annEntityaAttr.CollectionLocation.Longitude,
                    latitude: annEntityaAttr.CollectionLocation.Latitude));
                filter = Builders<AnnouncementEntity>.Filter.Near(a => a.CollectionLocation, point, annEntityaAttr.MaxDistanceFromLocationInKM * metersFor1KM);

Here is how I add the second filter:

var point = GeoJson.Point(GeoJson.Geographic(longitude: annEntityaAttr.DepositLocation.Longitude,
                    latitude: annEntityaAttr.DepositLocation.Latitude));
                var secondFilter = Builders<AnnouncementEntity>.Filter.Near(a => a.DepositLocation, point, annEntityaAttr.MaxDistanceFromLocationInKM * metersFor1KM);

filter = filter & secondFilter;

Normaly, when applying & to two filters, it works, but in this case, it doesn't please does someone have a solution for this ?.


Solution

  • you can only do one geo query on a single collection at a time. if you must store two coordinate fields in a single document, you will have to issue two seperate geo queries and then intersect the results on the client side. also you'd need to create 2 geo indexes and specify the index key when querying. here's an example program that uses my library MongoDB.Entities to achieve what you need.

    using MongoDB.Entities;
    using MongoDB.Driver;
    using System.Linq;
    
    namespace StackOverflow
    {
        public class Program
        {
            public class Announcement : Entity
            {
                public Coordinates2D CollectionLocation { get; set; }
                public Coordinates2D DepositLocation { get; set; }
                public double DistanceMeters { get; set; }
            }
    
            static void Main(string[] args)
            {
                new DB("test");
    
                DB.Index<Announcement>()
                  .Key(a => a.CollectionLocation, KeyType.Geo2DSphere)
                  .Create();
    
                DB.Index<Announcement>()
                  .Key(a => a.DepositLocation, KeyType.Geo2DSphere)
                  .Create();
    
                (new Announcement
                {
                    DepositLocation = new Coordinates2D(48.8539241, 2.2913515),
                    CollectionLocation = new Coordinates2D(48.796964, 2.137456)
                }).Save();
    
                var searchPointA = new Coordinates2D(48.796964, 2.137456);
    
                var queryA = DB.GeoNear<Announcement>(
                                    NearCoordinates: searchPointA,
                                    DistanceField: a => a.DistanceMeters,
                                    IndexKey: "CollectionLocation",
                                    MaxDistance: 10);
    
                var searchPointB = new Coordinates2D(48.8539241, 2.2913515);
    
                var queryB = DB.GeoNear<Announcement>(
                                    NearCoordinates: searchPointB,
                                    DistanceField: a => a.DistanceMeters,
                                    IndexKey: "DepositLocation",
                                    MaxDistance: 10);
    
                var resultA = queryA.ToList();
                var resultB = queryB.ToList();
    
                var common = resultA.Where(a => resultB.Any(b => b.ID == a.ID)).ToArray();
            }
        }
    }
    

    the following two $geoNear queries will be issued to find the locations:

    [
        {
            "$geoNear": {
                "near": {
                    "type": "Point",
                    "coordinates": [
                        48.8539241,
                        2.2913515
                    ]
                },
                "distanceField": "DistanceMeters",
                "spherical": true,
                "maxDistance": NumberInt("10"),
                "key": "DepositLocation"
            }
        }
    ]
    
    [
        {
            "$geoNear": {
                "near": {
                    "type": "Point",
                    "coordinates": [
                        48.796964,
                        2.137456
                    ]
                },
                "distanceField": "DistanceMeters",
                "spherical": true,
                "maxDistance": NumberInt("10"),
                "key": "CollectionLocation"
            }
        }
    ]