sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Las consultas geoespaciales funcionan en arreglos? ( $geoDentro, $geoIntersecciones )

Esta es una de esas preguntas que debe responder con sí y no, ya que sí, se admite una matriz para los resultados coincidentes, pero probablemente tampoco sea lo que realmente desea, considerando las restricciones sobre cómo se realiza la coincidencia.

El cambio notable que necesita aquí es que los objetos en sí mismos no están definidos de manera que MongoDB los reconozca tal como los tiene formados actualmente. Hay dos formularios de búsqueda generales y de índice, ya sea con pares de coordenadas heredados (que es solo un punto x, y) o como GeoJSON con objetos GeoJSON compatibles. Su problema es que tiene un formato GeoJSON "psuedo" que realmente no se ajusta a la especificación, y que está tratando de acceder a las "coordenadas" directamente, donde necesita un objeto de nivel superior como este:

{
    "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
                    ]
                ]]
            }
        }
    ]
}

Eso abstrae la parte de GeoJSON para que esté bien formada y separada de los otros metadatos que no forman parte de la especificación. Idealmente, también indexaría, aunque no es necesario para $geoWithin o $geoIntersects ciertamente ayuda:

db.regions.createIndex({ "regions.geometry": "2dsphere" })

Definición de la ruta completa a la definición de GeoJSON dentro del elemento de matriz.

Entonces las consultas funcionan correctamente:

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]
                ]]
            }
        }
    }
})

Que coincide con el documento anterior. Pero, por supuesto, hay múltiples objetos en la matriz, por lo que la pregunta es, ¿cuál de estos coincide? Para lo cual no hay una respuesta compatible, ya que MongoDB está haciendo coincidir el "documento" y no indica de ninguna manera qué elemento de la matriz coincidió.

Hay una opción en la agregación $geoNear eso permite que se devuelva el objeto coincidente, donde en este caso sería "el más cercano". Y con detalles como ese, entonces es posible usar esa información para hacer coincidir qué elemento de matriz con metadatos completos contiene el elemento que se encontró como "más cercano" y extraer esos datos. Pero nuevamente, es solo "cerca" y nunca puede devolver más de un resultado de una matriz.

Pero, en términos generales, es mejor simplemente separar los objetos como documentos en su propia colección, donde la coincidencia con el objeto distinto es solo una cuestión de hacer coincidir el documento. Entonces, con la matriz anterior en su propia colección, solo emite la consulta para la geometría coincidente:

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]
                ]]
            }
        }
    }
})

Lo que da los objetos correctos, ya que en este caso la forma se cruza con 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
            ]
        ]]
    }
}

Por lo tanto, puede usar matrices, pero solo puede hacer coincidir realmente el documento y no los miembros individuales de la matriz que formaron parte de la coincidencia, por lo que esto devolverá, por supuesto, los documentos en su conjunto y deberá determinar qué miembros coincidieron con los criterios en el código del cliente. .

En otra nota, varios de sus intentos de consulta buscan "dividir" la matriz de coordenadas del objeto en elementos individuales. Esto no se admite en absoluto, ya que el objeto solo se puede tratar como un todo y no como partes de "Punto".