1

Trying spatial lookup with Mongo, I've got 2 Collections.

The first "addresses" contains simple addresses locations :

{
    "id_addr" : "id1",
    "location" : {
        "type" : "Point",
        "coordinates" : [4.00,45.00]
    }
}

The second "zones" contains simple zone polygon definitions

{
    "id_zone" : "zone1",
    "location" : {
        "type" : "Polygon",
        "coordinates" : [[[3.00,40.00],[5.00,40.00],[5.00,45.00],[3.00,45.00], [3.00,40.00]]]
    }
}

I created on each collection a geospatial 2DSphere index on the location property.

I try to use the $geoWithin to find the addresses located in a zone. As a simple query, I'm looking for addresses located in my simple polygon. As simple :

db.adresses.find({"location" : { $geoWithin : { "$geometry" : { "type" : "Polygon", "coordinates" : [[[3.00,40.00],[5.00,40.00],[5.00,45.00],[3.00,45.00], [3.00,40.00]]]}}}})

returns my address point without any issue.

Now, I'm trying to aggregate a lookup on the zones collection. The idea is to join all addresses contained in the zones. So, my first stage of my zones aggregation looks like that :

$lookup{
  from: "adresses",
  let : {zonePolygon:"$location"},
  as: "zones",
  pipeline : [
    {
      $match : {
        location : {
          $geoWithin : {
            $geometry : "$$zonePolygon"
          }
        }       
      }
    }
  ]
}

but Mongo replies that unknown geo specifier: $geometry: "$$zonePolygon".

I tried to expand the $geometry property needed by $geoWithin, so :

$lookup : {
  from: "addresses",
  let : {zoneCoordinates:"$location.coordinates"},
  as: "zones",
  pipeline : [
    {
      $match : {
        location : {
          $geoWithin : {
            $geometry : {
              type :"Polygon",
              coordinates : "$$zoneCoordinates"
            }
          }
        }       
      }
    }
  ]
}

but now, mongo replies that "Polygon coordinates must be an array, instead got type string" ! It's like the $$zoneCoordinates Array isn't exposed and traited as a string...

Any idea ?

EDIT

Thanks to this question I finally solved my issue ! In fact, the mongo doc is clear : when variables are defined in the let field of a $lookup, they only can be used in a $expr operator of a $match stage in the pipeline. So, We'd need to pass the $geoWithin as an $expr statment.... but unfortunatly, mongo doesn't support $geoWithin as an expression for $expr...

The solution I found consists of using the $geoNear operator in the pipeline : $geoNear outputs documents in order of nearest to farthest from a specified point. So, starting from my points collection, I can use $lookup to 'join' all polygon Documents based of the distance between the point and the polygon... and if the polygon contains the point, the distance will be 0 !!!!

The $lookup stage of the aggregation I made on my "points" collection looks like :

{
  from: "polygons", 
  let : {pointGeometry : "$location"}, //here, we declare a "pointGeometry" var based on the "location" field of my point
  as: "zones",
  pipeline : [
    {
      $geoNear : {
        near : "$$pointGeometry", //no restriction to use the var in a $geoNear
        distanceField : "distance", //required : the distance field will be populate by the distance between my point and each polygon
        spherical : false,
        maxDistance : 0 //build in filter for max distance : 0 in this case means "if the polygon contains the point"
      }
    },
    {
      $project : {
        id_zone : 1, //I only keep the id_zone field (don't care of the polygon location)
        
      }
    }
  ]
}

It works like expected ! Each point contains now in the "zones" field an array of one polygon document that contains the point ! Just $unwind on the zones fields, and continue pipeline ($project, ...) to format the ouput documents as needed !

Hope it helps

3
  • This question is similar to: In MongoDB, how do I use a field in the document as input to a $geoWithin/$centerSphere expression?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Oct 9, 2024 at 17:01
  • I think using variables as input to $geoWithin is still yet to be supported by MongoDB. Commented Oct 9, 2024 at 17:02
  • Thanks ray, I didn't see how your refered question could help, because of its talking about distance between points, but the $geoNear with polygons can be used to simultate a geoWithin (st_contains like) ! I solved my issue and will edit my question... it may help others ! Thanks ! Commented Oct 10, 2024 at 7:39

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.