sql >> Databasteknik >  >> NoSQL >> MongoDB

Fungerar geospatiala frågor på arrayer? ( $geoWithin, $geoIntersects )

Detta är en av dessa både ja- och nej-frågor att besvara, eftersom ja en array stöds för att matcha resultat i men det är förmodligen inte heller vad du verkligen vill ha med tanke på begränsningarna för hur matchningen görs.

Den anmärkningsvärda förändringen du behöver här är att själva objekten inte är definierade på ett sätt som MongoDB kommer att känna igen dem när du för närvarande har dem bildade. Det finns två index- och allmänna uppslagsformer, antingen med äldre koordinatpar (som bara är en x,y-punkt) eller som GeoJSON med GeoJSON-objekt som stöds. Ditt problem är att du har ett "psuedo" GeoJSON-format som inte riktigt överensstämmer med specifikationen och att du försöker komma åt "koordinaterna" direkt, där du behöver ett objekt på toppnivå som så:

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

Så det abstraherar GeoJSON-delen för att vara både välformad och separerad från andra metadata som inte är en del av specifikationen. Helst skulle du också indexera, även om det inte krävs för $geoWithin eller $geoIntersects det hjälper verkligen:

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

Definierar den fullständiga sökvägen till GeoJSON-definitionen inom arrayelementet.

Då fungerar frågor korrekt:

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

Vilket stämmer överens med dokumentet ovan. Men naturligtvis finns det flera objekt i arrayen, så frågan är vilken av dessa matchade? Till vilket det inte finns något som stöds, eftersom MongoDB matchar "dokumentet" och inte på något sätt indikerar vilket arrayelement som matchades.

Det finns ett alternativ i sammanställningen $geoNear som gör att det matchade objektet kan returneras, där det i det här fallet skulle vara "närmast". Och med sådan detalj är det sedan möjligt att använda den informationen för att matcha vilket arrayelement med full metadata som innehåller elementet som hittades för "närmast" och extrahera den datan. Men återigen är det bara "nära" och kan heller aldrig returnera mer än ett resultat från en array.

Men generellt sett är det bättre att bara utgå från de separata objekten som dokument i sin egen samling, där matchning till distinkt objekt bara är en fråga om att matcha dokumentet. Så med arrayen ovan i sin egen samling, skickar du bara frågan för den matchande geometrin:

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

Vilket ger rätt objekt då formen i detta fall skär båda:

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

Så du kan använda arrayer men du kan bara verkligen matcha dokument och inte de enskilda arraymedlemmarna som ingick i matchningen, så detta kommer naturligtvis att returnera dokument som helhet och du skulle behöva räkna ut vilka medlemmar som matchade kriterierna i klientkoden .

Dessutom försöker flera av dina frågeförsök att "bryta upp" objektkoordinatmatrisen i individuella element. Detta stöds inte alls eftersom objektet bara kan hanteras som en helhet och inte som det är "Point"-delar.




  1. MongoDB:Felaktig geofråga med $geoIntersect på en polygon

  2. Fjäderdata Redis HGETALL operation

  3. Inget svar efter anslutning från selleri till redis via ssl

  4. Varför väntar detta utanför async-funktionen?