问题
I would like to write a $near query with a $maxDistance argument whose value is not constant. For example, I have a collection of fire stations with a location and a coverage radius, and I want to find all fire stations whose coverage radius includes some specific point. The coverage radius can vary by station.
I have a collection full of documents that look like:
{
'loc' : [-72,40],
'radius' : 10
}
A query that looks something like:
{'loc': { $near : coordinates, $maxDistance : 'radius'}};
But that isn't correct.
If I were writing a SQL query, I would use something like:
SELECT * FROM table AS foo WHERE foo.radius ... (whatever your distance method looks like)
But I can't figure out how to access that radius variable in a mongo query. Is this even possible?
回答1:
You can't quite do this like this — in general you can not base anything in your MongoDB queries on values in the collections.
However, since MongoDB 2.4 we support a new index called 2dsphere
which allows you to store not only points in the database, but polygons as well. You'd store that information in a document like:
db.so.ensureIndex( { loc: '2dsphere' } );
db.so.insert( {
name: "Firestation 1",
loc: {
type: "Polygon",
coordinates: [ [ [ 0, 0 ], [ 0, 1 ], [ 1, 1 ], [ 1, 0 ], [ 0, 0 ] ] ]
}
} );
And then you can use an "intersect" query to figure out whether a point is covered by each of the polygons:
db.so.find( {
'loc' : {
$geoIntersects: {
$geometry: { type: 'Point', coordinates: [ 0, 0 ] }
}
}
} );
Which then returns:
{
"_id" : ObjectId("51f24d566775068ab0b786f0"),
"name" : "Firestation 1",
"loc" : {
"type" : "Polygon",
"coordinates" : [ [ [ 0, 0 ], [ 0, 1 ], [ 1, 1 ], [ 1, 0 ], [ 0, 0 ] ] ]
}
}
Here it finds the fire station, because 0, 0 is in the middle of the polygon. Now the trick is of course to calculate the polygon points that make up a circle that is "radius" (say 10km) away from the centre point. You won't be able to get a real circle, but a hexagon or octagon should be good enough. The maths for that isn't extremely simple, but http://www.movable-type.co.uk/scripts/latlong.html#destPoint has an example in JavaScript. Just loop your bearing in 8 steps from 0 to 2PI to calculate the points along the circumference of the circle, and put those in the coordinates. Make sure to embed them in a doubly nested array and make the first and the last one the same:
{
name: "Firestation 1",
loc: {
type: "Polygon",
coordinates: [ [
[ point1-lon, point1-lat ],
[ point2-lon, point2-lat ],
[ point3-lon, point3-lat ],
...
[ point1-lon, point1-lat ],
] ]
}
}
来源:https://stackoverflow.com/questions/17868480/using-an-object-property-as-the-maxdistance-argument-in-a-mongodb-geolocation-q