Использование геопространственных запросов Mongo для большого количества данных - PullRequest
8 голосов
/ 08 мая 2019

Я использую базу данных Mongo с mongoose в Nest, инфраструктуре сервера машинописи.

У меня есть 2 коллекции монго, одна содержит 20 000 пользовательских локаций. Другая коллекция содержит 10 000 точек интересов, собранных из Google Places API.

Теперь я хочу найти пересечения между собранными местоположениями и этими местами (которые содержат точку GeoJSON широты и lng).

Другими словами, я смотрю, где по отношению к пользователям этих POI были.

В настоящее время у меня есть асинхронный метод, который находит все местоположения, которые находятся рядом с точкой, используя оператор nearSphere.

Тогда я думаю, что следующим шагом будет итерация по каждому месту (10 000 из них) в коллекции монго и запуск этого метода в каждом месте. Таким образом, у меня будет список того, какие POI были «рядом», когда это конкретное местоположение было обнаружено.

Есть ли лучший способ сделать это? Что касается производительности, я считаю, что этот путь будет бороться. Я не могу найти геопространственный запрос, который позволил бы мне сравнить 2 набора местоположений вместе.

  • Получить все местоположения рядом с точкой
async findAllNearPlace(coords): Promise<Location[]> {
    return await this.locationModel.find(
      {
        location:
          { $nearSphere:
              {
                $geometry: { type: "Point",  coordinates: coords },
                $minDistance: 0,
                $maxDistance: 100
              }
          }
      }
    );
  }

Каждый POI - проверьте местоположения:

async findUsersInProximity(places): Promise<Location[]> {
    const locations = [];
    let i = places.length - 1;
    while (i > 0) {
      await this.findAllNearPlace(
        places[i].location.coordinates
      ).then(intersectingLocations => {
        locations.push(...intersectingLocations);
        i--;
      });
    }
    return await locations;
  }

Как и ожидалось, производительность этого невелика и занимает минуты.

1 Ответ

0 голосов
/ 22 мая 2019

Что вы, вероятно, можете сделать, это создать агрегатную функцию с поиском, я не проверял ее, и я не знаю точно, является ли она лучшей производительностью, но вы можете сделать что-то похожее на следующее:

let pipeline = [
        {
            $geoNear: {
                includeLocs: "location",
                distanceField: "distance",
                near: { type: 'Point', coordinates: "$$point" },
                maxDistance: 20,
                spherical: true
            }
        }
    ];

UsersModel.aggregate([{
   $lookup : {
     from : 'locations',
     let : {point : '$address'}, //whatever the field for the coordinates is 
     pipeline ,
     as : 'places'   
   }
}])
...