Существует ли запрос или агрегация, которая позволила бы мне сгенерировать определенное количество документов, содержащих случайно сгенерированное местоположение в пределах определенного диапазона (необязательно существующее в базе данных), и документ с ближайшим местоположением из этого сгенерированного местоположения.
Например, , сгенерировать 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