MongoDB geoNear со случайными координатами в пределах диапазона - PullRequest
0 голосов
/ 16 апреля 2019

Существует ли запрос или агрегация, которая позволила бы мне сгенерировать определенное количество документов, содержащих случайно сгенерированное местоположение в пределах определенного диапазона (необязательно существующее в базе данных), и документ с ближайшим местоположением из этого сгенерированного местоположения.

Например, , сгенерировать 10 координаты с долготой от -71.2 до -71.3 и с широтой от 46.7 до 46.9, и для каждых случайно сгенерированных координат выполните следующую агрегацию :

db.collection.aggregate([
    {
        $geoNear: {
            near: {
                type: "Point",
                coordinates: [
                    randomLng,
                    randomLat
                ]
            },
            distanceField: 'distance',
            spherical: true,
            limit: 1
        }
    }
])


Другими словами, я хотел бы сгенерировать определенное количество координат с соблюдением следующих правил:

  • Случайно сгенерированная долгота должна находиться в заданном диапазоне (например, -73.2 < lng < -71.1)
  • Случайно сгенерированная широта должна находиться в заданном диапазоне (например, 45.7 < lat < 46.4)

И для каждой сгенерированной координаты извлекайте ближайший существующий документ из коллекции. Короче говоря, для каждой сгенерированной координаты выполните вышеуказанную агрегацию.

Я попытался сгенерировать 10 координат с веб-сервера и одновременно запросить ближайший документ для каждого из них, но это занимает очень много времени.

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


UPDATE:

Мне удалось запросить случайные координаты в определенном диапазоне с помощью следующего:

/**
 * Generates random coordinates within a specified zone.
 *
 * @param {object} opts
 * @param {number} opts.lng - Longitude
 * @param {number} opts.lat - Latitude
 * @param {number} opts.offsetLng - Longitude's offset
 * @param {number} opts.offsetLat - Latitude's offset
 * @param {number} opts.qty - Number of documents to generate
 * @returns {Promise<any[]>}
 */
async function myQuery({ lng, lat, offsetLng, offsetLat, qty }) {

  // Generates a random number between 0 and 1
  const rdmExpr = {
    $abs: {
      $divide: [
        1,
        {
          $reduce: {
            input: {
              $map: {
                input: {
                  $range: [
                    0,
                    { $strLenCP: { $toString: '$_id' } }
                  ]
                },
                in: {
                  $substrCP: [
                    { $toString: '$_id' },
                    '$$this',
                    1
                  ]
                }
              }
            },
            initialValue: 0,
            in: {
              $add: [
                {
                  $convert: {
                    input: '$$this',
                    to: 'double',
                    onError: -(Math.PI - 1)
                  }
                },
                '$$value'
              ]
            }
          }
        }
      ]
    }
  }


  return await db.collection('coord').aggregate([
    {
      $sample: { size: qty }
    },
    { // Generates random coordinates within range
      $replaceRoot: {
        newRoot: {
          coords: [
            {
              $let: {
                vars: {
                  rdm: rdmExpr
                },
                in: {
                  $add: [
                    lng,
                    { $multiply: [ '$$rdm', offsetLng ] }
                  ]
                }
              }
            },
            {
              $let: {
                vars: {
                  rdm: rdmExpr
                },
                in: {
                  $add: [
                    lat,
                    { $multiply: [ '$$rdm', offsetLat ] }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  ]).toArray();
}

Но когда я пытаюсь добавить следующий конвейер $lookup для извлечения ближайшего документа из каждой сгенерированной координаты, я всегда получаю сообщение о том, что « поле рядом» должно быть точкой ».

{
  $lookup: {
    from: 'coord',
    let: {
      c: "$coords"
    },
    as: 'nearest',
      pipeline: [
      {
        $geoNear: {
          near: {
            type: 'Point',
            coordinates: "$$c"
          },
          distanceField: 'distance',
          spherical: true,
          limit: 1
        }
      }
    ]
  }
}

Что я делаю не так? Есть ли другой способ сделать это?

Примечание: Коллекция coord имеет поле location с индексом 2dsphere

...