2014년 12월 31일 수요일

MongoDB: Using $geoIntersects or $geoWithin with $near in one query

I would like to query for all documents that have a polygon that a point is contained in and then for that result set, order it based on closeness of that point to the location of the document.
So imagine I have a database of friends because I'm just that cool, and would like to see which friends are within the my range and would be willing to come play. (each friend has a play-date polygon which is the range they are willing to travel for a play-date)
For all matches I would like to them proceed to see which friend I should call to come based on his actual address and its distance to my point (which is my address) so that I can determine if I am ok with them coming from far away. (lets say 300 meters)
So far I have below a query to find polygons that my point is contained within but I do not know how to include the $near operator of mongodb
For JSON:
{ "_id" : "objid", "FRIEND_NAME" : "Bobby", "GEOMETRY" : {"type":"Polygon","coordinates":[[[-73.98779153823898,40.718233223261],[-74.004946447098,40.723575517498],[-74.006771211624,40.730592217474],[-73.99010896682698,40.746712376146], [-73.973135948181,40.73974615047701],[-73.975120782852,40.736128627654],[-73.973997695541,40.730787341083],[-73.983317613602,40.716639396436],[-73.98779153823898,40.718233223261]]]}, "FRIEND_POSITON" : { "lon" : -73.992188, "lat" : 40.729359 } }
This works:
db.friends.find({ "PLAYDATE_RANGE":{ "$geoIntersects":{ "$geometry":{ "type":"Point", "coordinates":[ -73.98652, 40.752044 ] } } } })
This does not:
db.friends.find([ { "PLAYDATE_RANGE":{ "$geoIntersects":{ "$geometry":{ "type":"Point", "coordinates":[ -73.98652, 40.752044 ] } } } }, { "FRIEND_POSITON":{ "$geoNear":{ "near":{ "type":"Point", "coordinates":[ -73.98652, 40.752044 ] }, "maxDistance":300 } } } ])
Please help me with the query above that does not work.



This requires an aggregate pipeline. As per mogodb doc for $geoNear, You can only use $geoNear as the first stage of a pipeline. The aggregate function has an entry for an additional query which is where the polygon query will be used to narraw down results based on inclusion in the PLAYDATE_RANGE field of the document.
db.friends.aggregate([
   {
     $geoNear: {
        near: { type: "Point", coordinates: [ -73.98652 , 40.752044 ] },
        maxDistance: 300,
        distanceField: "friends.calculated_distance",
        query: {
       "PLAYDATE_RANGE":{
          "$geoIntersects":{
             "$geometry":{
                "type":"Point",
                "coordinates":[
                   -73.98652,
                   40.752044
                ]
             }
          }
       }
    },
        spherical: true

     }
   }
])
P.S. note that only one geospatial index can be used so put it on the FRIEND_POSITION field. If adding a 2sphere index that requires a correctly formed GeoJSON value, specifically,
"FRIEND_POSITION" : { "type" : "Point", "coordinates" : [ -73.992188, 40.729359 ] }
So the document should look like:
{ "_id" : "objid", "FRIEND_NAME" : "Bobby", "GEOMETRY" : {"type":"Polygon","coordinates":[[[-73.98779153823898,40.718233223261],[-74.004946447098,40.723575517498],[-74.006771211624,40.730592217474],[-73.99010896682698,40.746712376146],    [-73.973135948181,40.73974615047701],[-73.975120782852,40.736128627654],[-73.973997695541,40.730787341083],[-73.983317613602,40.716639396436],[-73.98779153823898,40.718233223261]]]}, "FRIEND_POSITION" : { "type" : "Point", "coordinates" : [ -73.992188, 40.729359 ] } }


댓글 없음:

댓글 쓰기