MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

As consultas geoespaciais funcionam em arrays? ( $geoWithin, $geoIntersects )


Esta é uma daquelas perguntas sim e não para responder, pois sim, uma matriz é suportada para resultados correspondentes, mas também provavelmente não é o que você realmente deseja, considerando as restrições sobre como a correspondência é feita.

A mudança notável que você precisa aqui é que os próprios objetos não são definidos de uma forma que o MongoDB irá reconhecê-los como você os formou atualmente. Existem dois formulários de pesquisa geral e de índice com pares de coordenadas herdados (que é apenas um ponto x,y) ou como GeoJSON com objetos GeoJSON suportados. Seu problema é que você tem um formato GeoJSON "psuedo" que realmente não está em conformidade com a especificação e que está tentando acessar as "coordenadas" diretamente, onde precisa de um objeto de nível superior assim:
{
    "regions": [
        {
            "name": "penta",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ], 
                    [ 
                        -77.0336792618036270, 
                        -12.1255133434450870
                    ], 
                    [ 
                        -77.0326449349522590, 
                        -12.1239143495252150
                    ], 
                    [ 
                        -77.0300991833209990, 
                        -12.1238251884504540
                    ], 
                    [ 
                        -77.0299865305423740, 
                        -12.1262000752832540
                    ], 
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ]
                ]]
            }
        },
        {
            "name": "triangle",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ], 
                    [ 
                        -77.0325788855552670, 
                        -12.1246968022373030
                    ], 
                    [ 
                        -77.0300653204321860, 
                        -12.1246233756874440
                    ], 
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ]
                ]]
            }
        }
    ]
}

Portanto, isso abstrai a parte GeoJSON para ser bem formada e separada dos outros metadados que não fazem parte da especificação. Idealmente, você também indexaria, embora não seja necessário para $geoWithin ou $geoIntersects certamente ajuda:
db.regions.createIndex({ "regions.geometry": "2dsphere" })

Definindo o caminho completo para a definição GeoJSON dentro do elemento da matriz.

Então as consultas funcionam corretamente:
db.regions.find({
    "regions.geometry" : { 
        "$geoIntersects" : { 
            "$geometry" : { 
                "type" : "Polygon" , 
                "coordinates" : [[
                    [ -77.02877718955278 , -12.123750122669545],
                    [ -77.03457042574883 , -12.123750122669545],
                    [ -77.03457042574883 , -12.12736341792724],
                    [ -77.02877718955278 , -12.12736341792724], 
                    [ -77.02877718955278 , -12.123750122669545]
                ]]
            }
        }
    }
})

O que corresponde ao documento acima. Mas é claro que existem vários objetos na matriz, então a questão é:qual deles corresponde? Para o qual não há resposta suportada, pois o MongoDB está correspondendo ao "documento" e não indica de forma alguma qual elemento da matriz foi correspondido.

Existe uma opção na agregação $geoNear que permite que o objeto correspondido seja retornado, onde neste caso seria "mais próximo". E com detalhes como esse é possível usar essa informação para combinar qual elemento do array com metadados completos contém o elemento que foi encontrado para "mais próximo" e extrair esses dados. Mas, novamente, é apenas "próximo" e também nunca pode retornar mais de um resultado de uma matriz.

Mas, de um modo geral, é melhor apenas separar os objetos como documentos em sua própria coleção, onde a correspondência com o objeto distinto é apenas uma questão de correspondência do documento. Então, com o array acima em sua própria coleção, você apenas emite a consulta para a geometria correspondente:
db.shapes.find({
    "geometry" : { 
        "$geoIntersects" : { 
            "$geometry" : { 
                "type" : "Polygon" , 
                "coordinates" : [ [ 
                    [ -77.02877718955278 , -12.123750122669545],
                    [ -77.03457042574883 , -12.123750122669545],
                    [ -77.03457042574883 , -12.12736341792724],
                    [ -77.02877718955278 , -12.12736341792724], 
                    [ -77.02877718955278 , -12.123750122669545]
                ]]
            }
        }
    }
})

O que fornece o(s) objeto(s) correto(s), pois neste caso a forma cruza ambos:
{
    "_id" : ObjectId("55f8d2fa66c2e7c750414b7a"),
    "name" : "penta",
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [[
            [
                    -77.03228048980236,
                    -12.127106755278156
            ],
            [
                    -77.03367926180363,
                    -12.125513343445087
            ],
            [
                    -77.03264493495226,
                    -12.123914349525215
            ],
            [
                    -77.030099183321,
                    -12.123825188450454
            ],
            [
                    -77.02998653054237,
                    -12.126200075283254
            ],
            [
                    -77.03228048980236,
                    -12.127106755278156
            ]
        ]]
    }
}
{
    "_id" : ObjectId("55f8d2fa66c2e7c750414b7b"),
    "name" : "triangle",
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [[
            [
                    -77.03135680407286,
                    -12.126657349201809
            ],
            [
                    -77.03257888555527,
                    -12.124696802237303
            ],
            [
                    -77.03006532043219,
                    -12.124623375687444
            ],
            [
                    -77.03135680407286,
                    -12.126657349201809
            ]
        ]]
    }
}

Portanto, você pode usar matrizes, mas só pode realmente corresponder ao documento e não aos membros individuais da matriz que faziam parte da correspondência, portanto, isso retornará os documentos do curso como um todo e você precisaria descobrir quais membros corresponderam aos critérios no código do cliente .

Em outra nota, várias de suas tentativas de consulta procuram "dividir" a matriz de coordenadas do objeto em elementos individuais. Isso não é suportado, pois o objeto só pode ser tratado como um todo e não como partes de "Ponto".