sql >> Databáze >  >> NoSQL >> MongoDB

Fungují geoprostorové dotazy na polích? ( $geoWithin, $geoIntersects )

Toto je jedna z těch otázek, na které je třeba odpovědět ano i ne, protože ano, pole je podporováno pro porovnávání výsledků, ale pravděpodobně to také není to, co skutečně chcete, s ohledem na omezení týkající se způsobu porovnávání.

Pozoruhodnou změnou, kterou zde potřebujete, je to, že samotné objekty nejsou definovány tak, aby je MongoDB rozpoznal tak, jak je aktuálně máte vytvořené. Existují dva indexové a obecné vyhledávací formuláře buď se staršími páry souřadnic (což je pouze bod x, y) nebo jako GeoJSON s podporovanými objekty GeoJSON. Váš problém je, že máte "psuedo" formát GeoJSON, který skutečně neodpovídá specifikaci, a že se pokoušíte přistupovat přímo k "souřadnicím", kde potřebujete objekt nejvyšší úrovně, jako je tento:

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

Takže to abstrahuje část GeoJSON, aby byla dobře tvarovaná a oddělená od ostatních metadat, která nejsou součástí specifikace. V ideálním případě byste také indexovali, i když to není nutné pro $geoWithin nebo $geoIntersects určitě to pomáhá:

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

Definování úplné cesty k definici GeoJSON v prvku pole.

Pak dotazy fungují správně:

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

Což odpovídá dokumentu výše. Ale v poli je samozřejmě více objektů, takže otázkou je, který z nich se shoduje? Na což neexistuje žádná podporovaná odpověď, protože MongoDB odpovídá „dokumentu“ a žádným způsobem neoznačuje, který prvek pole byl spárován.

V agregaci je možnost $geoNear to umožňuje vrátit odpovídající objekt, kde by v tomto případě byl „nejbližší“. A s podobnými podrobnostmi je pak možné tyto informace použít k porovnání, který prvek pole s úplnými metadaty obsahuje prvek, který byl nalezen pro „nejbližší“, a extrahovat tato data. Ale opět je pouze "blízko" a také nemůže nikdy vrátit více než jeden výsledek z pole.

Ale obecně řečeno je lepší pouze samostatné objekty jako dokumenty v jejich vlastní sbírce, kde shoda s odlišným objektem je pouze záležitostí shody s dokumentem. Takže s polem výše v jeho vlastní kolekci stačí zadat dotaz na odpovídající geometrii:

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

Což dává správný objekt(y), protože v tomto případě tvar protíná oba:

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

Takže můžete použít pole, ale můžete skutečně spárovat pouze dokument a ne jednotlivé členy pole, které byly součástí shody, takže to samozřejmě vrátí dokumenty jako celek a budete muset zjistit, kteří členové odpovídali kritériím v kódu klienta .

Další poznámka, několik vašich pokusů o dotaz se snaží „rozdělit“ pole souřadnic objektů na jednotlivé prvky. To není vůbec podporováno, protože s objektem lze zacházet pouze jako s celkem a ne jako s jeho "bodovými" částmi.




  1. Nelze se připojit k MongoDB přes node.js v Dockeru

  2. Jak přidat objednávku pomocí @query v úložišti mongodb

  3. jak spustit nativní dotaz mongodb s funkcí data mongodb v spring-data-mongodb?

  4. Jak na to:Testování aplikací HBase pomocí oblíbených nástrojů