sql >> Database >  >> NoSQL >> MongoDB

Werken geospatiale query's op arrays? ($geoWithin, $geoIntersects)

Dit is een van die zowel ja- als nee-vragen om te beantwoorden, want ja, een array wordt ondersteund voor het matchen van resultaten, maar het is waarschijnlijk ook niet wat u echt wilt, gezien de beperkingen op hoe het matchen wordt gedaan.

De opmerkelijke verandering die je hier nodig hebt, is dat de objecten zelf niet zo zijn gedefinieerd dat MongoDB ze zal herkennen zoals je ze momenteel hebt gevormd. Er zijn twee index- en algemene opzoekformulieren, ofwel met legacy-coördinaatparen (wat slechts een x,y-punt is) of als GeoJSON met ondersteunde GeoJSON-objecten. Uw probleem is dat u een "psuedo" GeoJSON-indeling heeft die niet echt voldoet aan de specificaties, en dat u rechtstreeks toegang probeert te krijgen tot de "coördinaten", waarbij u een object op het hoogste niveau nodig hebt, zoals:

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

Dus dat abstraheert het GeoJSON-gedeelte om zowel goed gevormd als gescheiden te zijn van de andere metagegevens die geen deel uitmaken van de specificatie. Idealiter zou je ook indexeren, maar niet vereist voor $geoWithin of $geoIntersects het helpt zeker:

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

Het volledige pad naar de GeoJSON-definitie binnen het array-element definiëren.

Dan werken zoekopdrachten correct:

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

Wat overeenkomt met het document hierboven. Maar er zijn natuurlijk meerdere objecten in de array, dus de vraag is, welke van deze kwamen overeen? Waarop geen ondersteund antwoord is, omdat MongoDB overeenkomt met het "document" en op geen enkele manier aangeeft welk array-element overeenkomt.

Er is een optie in de aggregatie $geoNear waardoor het overeenkomende object kan worden geretourneerd, waar het in dit geval "dichtstbijzijnde" zou zijn. En met zo'n detail is het dan mogelijk om die informatie te gebruiken om te matchen welk array-element met volledige metadata het element bevat dat is gevonden voor "dichtstbijzijnde" en die gegevens te extraheren. Maar nogmaals, het is alleen "near" en kan ook nooit meer dan één resultaat van een array retourneren.

Maar over het algemeen is het beter om de afzonderlijke objecten gewoon als documenten in hun eigen collectie te plaatsen, waarbij de match met het afzonderlijke object slechts een kwestie is van het matchen van het document. Dus met de array hierboven in zijn eigen verzameling, geef je gewoon de vraag voor de overeenkomende geometrie:

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

Wat het (de) juiste object(en) geeft, want in dit geval snijdt de vorm beide:

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

U kunt dus arrays gebruiken, maar u kunt alleen documenten echt matchen en niet de individuele arrayleden die deel uitmaakten van de match, dus dit zal natuurlijk documenten als geheel retourneren en u zou moeten uitzoeken welke leden aan de criteria in de klantcode voldoen .

Aan de andere kant proberen verschillende van uw zoekopdrachten om de objectcoördinatenarray op te splitsen in afzonderlijke elementen. Dit wordt helemaal niet ondersteund, omdat het object alleen als geheel kan worden behandeld en niet omdat het "punt"-onderdelen zijn.




  1. Heb een probleem bij het splitsen en tellen van de gegevens in een CSV in MONGODB (Null-waarden hebben in kolommen zoals kolomnaam:)

  2. Schema's in externe module werken niet in Node.js

  3. Kan niet lezen/schrijven op een MongoDB Atlas-database met Mongoose

  4. Is er een multicore-exploiterend NoSQL-systeem?