Что ж, на самом деле он описан в самой первой ссылке, поскольку поле "distanceMultipler"
можно использовать для преобразования между «радианами», которые возвращаются, когда данные не сохраняются в GeoJSON и используют устаревшие пары координат в любом принятый формат.
Из документации $geoNear
для опции "distanceField"
:
Дополнительно. Коэффициент для умножения всех расстояний, возвращаемых запросом. Например, используйте distanceMultiplier для преобразования радиан, возвращаемых сферическим запросом, в километры путем умножения на радиус Земли.
А из Расчет расстояния с использованием сферической геометрии
- расстояние до радиан: разделите расстояние на радиус сферы (например, Земли) в тех же единицах, что и при измерении расстояния.
- радианы к расстоянию: умножьте радиан на радиус сферы (например, Земли) в системе единиц, в которую вы хотите преобразовать расстояние.
Экваториальный радиус Земли составляет приблизительно 3 963,2 миль или 6 378,1 км.
Поэтому вы просто заполняете опции:
db.collection.aggregate([
{ "$geoNear": {
"near": [<longitude>,<latitude>],
"distanceField": "distance",
"spherical": true,
"distanceMultiplier": 6378.1 // convert radians to kilometers
}}
])
Или, если вы действительно внимательно прочитаете документацию, вы увидите, что для условий, поставленных для "near"
, есть особый случай, опция "spherical"
:
Если true, то MongoDB использует сферическую геометрию для вычисления расстояний в метрах, если указанная (ближняя) точка является точкой GeoJSON, и в радианах, если указанная (ближняя) точка является устаревшей парой координат.
Таким образом, простое предоставление запрашиваемых координат в формате GeoJSON возвращает метров , независимо от формата хранения:
db.collection.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [<longitude>,<latitude>]
},
"distanceField": "distance",
"spherical": true
}}
])
Также обратите внимание, что в отличие от некоторых других операторов "запроса", для этапа конвейера агрегации $geoNear
требуется , чтобы у вас было только один геопространственный индекс в коллекции , Нельзя указать «имя поля» для запроса, поскольку в формате команды ожидается, что в коллекции будет присутствовать только только один индекс типа "2d"
или "2dsphere"
. В любом случае вам нужен только один, но вы должны знать об этом.
обязательные опции для $geoNear
являются, конечно, аргументами для "near"
для координат для поиска, и "distanceField"
, который возвращает фактическое вычисленное расстояние в пределах возвращенные документы. "spherical"
требуется для "2dsphere"
индексов, которые вы должны использовать для точного измерения, и, конечно, "distanceMultiplier"
является полностью необязательным, но повлияет на результат, возвращаемый в свойстве, указанном "distanceField"
.
Существуют и другие варианты в зависимости от того, нужны ли вам дополнительные условия или ограничения запроса, но они являются основными для целей этого упражнения.
Также обратите внимание на порядок "longitude"
и "latitude"
. Это обязательный для правильной работы геопространственных запросов MongoDB. Если ваши данные имеют эти значения в обратном порядке (как это может быть в случае, когда они получены из других API-интерфейсов), вам необходимо исправить это, либо просто поменять местами сохраненный порядок, либо, что еще лучше, полностью конвертировать в GeoJSON.
Преобразование GeoJSON
Конечно, другой вариант - просто обновить ваши данные для фактического использования формата GeoJSON:
var ops = [];
db.colllection.find({ "coordinate": { "$exists": true } }).forEach( doc => {
ops.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": { "location": { "type": "Point", "coordinates": doc.coordinate } },
"$unset": { "coordinate": "" }
}
}
});
if ( ops.length >= 1000 ) {
db.collection.bulkWrite(ops);
ops = [];
}
})
if ( ops.length > 0 ) {
db.collection.bulkWrite(ops);
ops = [];
}
А затем отбросьте любой предыдущий индекс и создайте новый:
db.collection.dropIndex({ "coordinate": "2dpshere" })
db.collection.createIndex({ "location": "2dsphere" })
Конечно, во всех случаях меняйте collection
на фактическое имя коллекции.
Затем вы можете выполнять запросы, используя аргументы GeoJSON, и просто возвращать расстояния в метрах согласно стандарту.
Любой из этих вариантов является жизнеспособным, но в действительности использование GeoJSON должно поддерживать совместимость с большинством других видов использования внешней библиотеки, а также поддерживать поддержку всех операций геопространственных запросов MongoDB.