Представьте себе базу данных, в которой хранится позиция (широта, долгота) в каждом документе. Теперь представьте, что у нас есть несколько непересекающихся зон, каждая из которых описывается многоугольником. В одном запросе агрегации я хотел бы сопоставить положение в любой из этих зон, но также получить соответствующий номер зоны.
Я могу легко проверить один полигон.
db.AIS.aggregate(
[
{ $match: {
"pos": {
$geoWithin: {
$geometry: {
type : "Polygon" ,
coordinates: [ [
[
-3.581170042968779,
53.306942923437504
],
[
-3.56640117304687,
53.301085313281256
],
.....
}
}
}
]
);
И многоугольник здесь можно заменить на многоугольник, или вы можете использовать $ или в матче. НО, если вы хотите узнать, какое совпадение имело место, и добавить новое поле для указания этого, то это выглядит так, как будто это невозможно сделать на этапе $ match , поскольку это только возвращает неизмененные сопоставленные документы на следующий этап конвейера. ,
Может ли кто-нибудь предложить подходящий конвейер для решения этого общего шаблона сопоставления для нескольких исключительных условий и добавления выходного поля на основе сопоставления?
Дополнительные примечания
Я понимаю, что $ geoIntersects может работать в любую сторону, например, точка пересекает многоугольник или многоугольник пересекает точку. Рассматривая пример, в котором кто-то пытался определить, в каком полигоне (-ах) содержалась конкретная точка, у меня появилась идея сохранить все мои многоугольники в другой коллекции, а затем выполнить $ lookup , передавая каждую точку $ geoIntersects совпадение. ОДНАКО синтаксически кажется, что эти геопространственные запросы НЕ поддерживают ничего, кроме константных данных для геометрической части, и что невозможно использовать поле, отобранное из коллекции. Я не прав здесь?
Если на самом деле в настоящее время нет способа выполнить этот запрос, то я думаю, что мое решение будет таким, где мне в конечном итоге придется извлекать ВСЕ данные точек и выполнять собственные тесты пересечения многоугольников. Поскольку каждая коллекция точек, вероятно, будет содержать около 12 Гб / год, такие запросы будут в конечном итоге перемещать горы данных. Горы, которые я бы предпочел оставить в базе данных.
Кто-нибудь успешно использовал $ geoWithin или $ geoIntersects , где и позиция, и полигон (или другая геометрия) являются полями в коллекции. например, вероятно, в стадии $ lookup . Кто-нибудь может заявить, возможно ли это, или предложить альтернативное решение?
Более краткие эксперименты ...
Конечно, можно использовать агрегацию $ facet , например, следующим образом:
db.AIS.aggregate([
{
$facet: {
"zone_0": [
{ $match: { "pos": {$geoWithin: { $geometry: poly[0] } } } },
{ $group: {
_id: null,
n: { $sum: 1 }
}}
],
"zone_1": [
{ $match: { "pos": {$geoWithin: { $geometry: poly[1] } } } },
{ $group: {
_id: null,
n: { $sum: 1 }
}}
]
}
}
]);
Где poly - это массив полигонов GeoJSON, инициализированный в коде JS
Однако это, безусловно, проверяет каждую точку на предмет всех полигонов. Это также означает, что, когда многоугольники зон касаются друг друга, возможно, что точка совпадает с двумя зонами. Тестирование этого на реальной базе данных только с 2Gb точечных данных (проводной тигр) заняло много много минут только для двух полигонов. Кажется, он не очень хорошо масштабируется, и поскольку массовый поиск всех данных выполняется быстрее, чем запрос такого рода, тогда, возможно, имеет смысл выполнить обработку за пределами Mongo.
Может быть, в будущем что-то вроде условного $ addFields , но с синтаксисом, подобным $ match , может быть полезным, но, насколько я знаю, его не существует , Также могут помочь некоторые простые логические операторы геопространственного сравнения (например, стиль функции $ geoWithin / Intersects - используемый в $ project ).
Когда набор данных содержит как позиции, так и время, вам может не только потребоваться пересортировать результаты, но также может оказаться, что вы не воспользуетесь индексом 2dsphere (если сначала отфильтруете по времени).
Другие могут хранить геопространственные данные, подобные моим, и хотят выполнять аналогичную обработку, поэтому, если вы там, пожалуйста, поделитесь своими мыслями.