Это должно работать:
db.collection.aggregate([
{
"$match": {
"location": {
"$geoWithin": {
"$box": [
[0.024719919885622943, 51.54643953472475],
[-0.1589577534542408, 51.47239969138267]
]
}
}
}
},
{ $set: { lon: -0.0649729793707321 } },
{ $set: { lat: 51.50160291888072 } },
{
$set: {
distance: {
$let: {
vars: {
dlon: { $degreesToRadians: { $subtract: [{ $arrayElemAt: ["$location.coordinates", 0] }, "$lon"] } },
dlat: { $degreesToRadians: { $subtract: [{ $arrayElemAt: ["$location.coordinates", 1] }, "$lat"] } },
lat1: { $degreesToRadians: { $arrayElemAt: ["$location.coordinates", 1] } },
lat2: { $degreesToRadians: "$lat" }
},
in: {
// Haversine formula: sin²(dLat / 2) + sin²(dLon / 2) * cos(lat1) * cos(lat2);
$add: [
{ $pow: [{ $sin: { $divide: ["$$dlat", 2] } }, 2] },
{ $multiply: [{ $pow: [{ $sin: { $divide: ["$$dlon", 2] } }, 2] }, { $cos: "$$lat1" }, { $cos: "$$lat2" }] }
]
}
}
}
}
},
{
$set: {
distance: {
// Distance in Meters given by "6372.8 * 1000"
$multiply: [6372.8, 1000, 2, { $asin: { $sqrt: "$distance" } }]
}
}
},
])
Просто примечание, $box
используется только для Устаревшие пары координат . Для правильного запроса (т. Е. Правильного использования 2dsphere
index) вы должны использовать $geometry
:
db.collection.createIndex({ location: "2dsphere" })
db.collection.find(
{
"location": {
"$geoWithin": {
"$geometry": {
type: "Polygon",
coordinates: [[
[-0.1589577534542408, 51.47239969138267],
[-0.1589577534542408, 51.54643953472475],
[0.024719919885622943, 51.54643953472475],
[0.024719919885622943, 51.47239969138267],
[-0.1589577534542408, 51.47239969138267]
]]
}
}
}
}
).explain().queryPlanner.winningPlan.inputStage.indexName
--> location_2dsphere // which means index is used
db.collection.find(
{
"location": {
"$geoWithin": {
"$box": [
[0.024719919885622943, 51.54643953472475],
[-0.1589577534542408, 51.47239969138267]
]
}
}
}
).explain().queryPlanner.winningPlan.stage
--> COLLSCAN // which means full collection scan
или правильное использование устаревших координат:
db.collection.createIndex({ "location.coordinates": "2d" })
db.collection.find(
{
"location.coordinates": { // <- note this difference
"$geoWithin": {
"$box": [
[0.024719919885622943, 51.54643953472475],
[-0.1589577534542408, 51.47239969138267]
]
}
}
}
).explain().queryPlanner.winningPlan.inputStage.indexName
--> location.coordinates_2d