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
$geoWithinis still yet to be supported by MongoDB.