агрегация монго "совпадение" на нескольких исключительных условиях с результатом совпадения - PullRequest
0 голосов
/ 24 мая 2019

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

Я могу легко проверить один полигон.

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 (если сначала отфильтруете по времени).

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

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