Рассчитать расстояние точка-точка в километрах на этапах трубопровода - PullRequest
0 голосов
/ 30 апреля 2018

Этот документ возвращается по этапам конвейера агрегации:

//1
{
    "_id" : {
        "h" : 8,
        "d" : 6,
        "m" : 3,
        "y" : 2017
    },
    "docs" : [ ....],
"firstDoc" : {
    "ts" : ISODate("2017-03-06T08:07:21.008Z"),
    "coordinate" : [ 
        59.5......, 
        36.2......
    ]
   }
} ,
//2
{

} , // 3 , 4 

У меня есть 4 документа, как указано выше, эти поля firstDoc отличаются. Теперь я хочу вычислить расстояние между точками в километре. Вот так:

coordinate1---km?---coordinate2
coordinate2---km?---coordinate3
coordinate3---km?---coordinate4

Я вижу эту ссылку , но я не использую GeoJSON и не хочу proximity. Я хочу рассчитать расстояние между точками Как я могу это сделать? Я много искал, но не могу найти результат в mongoDB !!

Я видел, как парни делали это другим языком, таким как java и c # и java Script но никто не делал с монго-запросом. Возможно ли это с mongoDB?

1 Ответ

0 голосов
/ 30 апреля 2018

Что ж, на самом деле он описан в самой первой ссылке, поскольку поле "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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...