MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Работят ли геопространствените заявки върху масиви? ($geoWithin, $geoIntersects)

Това е един от тези въпроси с „да“ и „не“, на които трябва да се отговори, тъй като да, масив се поддържа за съпоставяне на резултати, но също така вероятно не е това, което наистина искате, като се имат предвид ограниченията за това как се извършва съпоставянето.

Забележителната промяна, от която се нуждаете тук, е, че самите обекти не са дефинирани по начин, по който MongoDB ще ги разпознае, както сте ги формирали в момента. Има две индексни и общи формуляри за търсене, които са или с наследени координатни двойки (което е само x,y точка), или като GeoJSON с поддържани GeoJSON обекти. Вашият проблем е, че имате "psuedo" GeoJSON формат, който всъщност не отговаря на спецификацията, и че се опитвате да получите директен достъп до "координатите", където имате нужда от обект от най-високо ниво като този:

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

Така че това абстрахира частта GeoJSON да бъде както добре оформена, така и отделена от другите метаданни, които не са част от спецификацията. В идеалния случай също бихте индексирали, макар че не е задължително за $geoWithin или $geoIntersects със сигурност помага:

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

Дефиниране на пълния път до дефиницията на GeoJSON в елемента на масива.

Тогава заявките работят правилно:

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

Което отговаря на горния документ. Но, разбира се, има множество обекти в масива, така че въпросът е кой от тях съвпада? На който няма поддържан отговор, тъй като MongoDB съвпада с „документа“ и не посочва по никакъв начин кой елемент от масива е съпоставен.

Има опция в агрегацията $geoNear това позволява да се върне съответстващият обект, където в този случай той би бил "най-близкият". И с подробности като тези тогава е възможно да се използва тази информация, за да се съпостави кой елемент от масив с пълни метаданни съдържа елемента, който е намерен за „най-близкия“, и да се извлекат тези данни. Но отново е само "близо" и никога не може да върне повече от един резултат от масив.

Но най-общо казано е по-добре отделните обекти да бъдат само като документи в тяхната собствена колекция, където съвпадението с отделен обект е просто въпрос на съвпадение на документа. Така че с масива по-горе в неговата собствена колекция, вие просто задавате заявката за съответстващата геометрия:

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

Което дава правилния обект(и), тъй като в този случай формата пресича и двата:

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

Така че можете да използвате масиви, но можете наистина да съпоставите само документ, а не отделните членове на масива, които са били част от съвпадението, така че това ще върне документите на курса като цяло и ще трябва да разберете кои членове отговарят на критериите в клиентския код .

От друга страна, няколко от вашите опити за заявка се стремят да "разбият" масива с координати на обекта на отделни елементи. Това изобщо не се поддържа, тъй като с обекта може да се работи само като цяло, а не като негови "точкови" части.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB:Как да актуализирам единичен поделемент в масив, посочен от индекса в масива?

  2. Неизменни ли са данните, върнати от Mongoose?

  3. Условно актуализиране на множество редове

  4. Как мога да актуализирам множество документи в mongoose?

  5. Ruby/релси:mongoid с mongo(скъпоценен камък); bson конфликт? Как да се справим с различните версии?